From 3fd08883beb4aec32b52adcd57b93e5998125dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 12 Nov 2024 09:17:27 +0000 Subject: [PATCH 01/13] feat(bulk-mileage): update errors (#16720) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: display latest reg * feat: add error code map * feat: add errors * fix: csv parse * fix: jobs sorting * fix: remove strip * fix: translations * fix: add sanitization on number * fix: sanitization * fix: add secret from aws paramter store * fix: sanitize bit less powerfully * fix: more handling * Update libs/service-portal/assets/src/screens/VehicleBulkMileageUpload/VehicleBulkMileageUpload.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: coderabbit suggestions --------- Co-authored-by: Ásdís Erna Guðmundsdóttir Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- libs/api/domains/vehicles/project.json | 6 ++ ...BulkVehicleMileageRequestOverview.input.ts | 4 + libs/api/domains/vehicles/src/lib/messages.ts | 83 +++++++++++++++++ ...lkMileageRegistrationRequestError.model.ts | 8 +- .../src/lib/resolvers/bulkMileage.resolver.ts | 1 + .../src/lib/services/bulkMileage.service.ts | 27 +++++- .../vehicles/src/lib/services/errorCodes.ts | 24 +++++ .../src/lib/services/vehicles.service.ts | 14 ++- .../vehicles/src/lib/vehicles.module.ts | 2 + .../vehicles-mileage/src/clientConfig.json | 20 ++-- .../service-portal/assets/src/lib/messages.ts | 19 ++++ .../VehicleBulkMileage/VehicleBulkMileage.tsx | 79 ++++++++-------- .../VehicleBulkMileageRow.tsx | 50 +++++++--- .../VehicleBulkMileageJobDetail.graphql | 2 + .../VehicleBulkMileageJobDetail.tsx | 41 +++++---- .../VehicleBulkMileageJobOverview.tsx | 23 +++-- .../VehicleBulkMileageUpload.tsx | 91 ++++++++++--------- .../assets/src/utils/parseFileToMileage.ts | 48 ++++++---- 18 files changed, 382 insertions(+), 160 deletions(-) create mode 100644 libs/api/domains/vehicles/src/lib/messages.ts create mode 100644 libs/api/domains/vehicles/src/lib/services/errorCodes.ts diff --git a/libs/api/domains/vehicles/project.json b/libs/api/domains/vehicles/project.json index 12892a54a5b4..b08b0b11eb44 100644 --- a/libs/api/domains/vehicles/project.json +++ b/libs/api/domains/vehicles/project.json @@ -14,6 +14,12 @@ "options": { "jestConfig": "libs/api/domains/vehicles/jest.config.ts" } + }, + "extract-strings": { + "executor": "nx:run-commands", + "options": { + "command": "yarn ts-node -P libs/localization/tsconfig.lib.json libs/localization/scripts/extract 'libs/api/domains/vehicles/src/lib/messages.ts'" + } } } } diff --git a/libs/api/domains/vehicles/src/lib/dto/getBulkVehicleMileageRequestOverview.input.ts b/libs/api/domains/vehicles/src/lib/dto/getBulkVehicleMileageRequestOverview.input.ts index 65b238fb9150..3ad3e1bb1e97 100644 --- a/libs/api/domains/vehicles/src/lib/dto/getBulkVehicleMileageRequestOverview.input.ts +++ b/libs/api/domains/vehicles/src/lib/dto/getBulkVehicleMileageRequestOverview.input.ts @@ -1,7 +1,11 @@ import { Field, ID, InputType } from '@nestjs/graphql' +import type { Locale } from '@island.is/shared/types' @InputType() export class BulkVehicleMileageRequestOverviewInput { + @Field(() => String) + locale!: Locale + @Field(() => ID) guid!: string } diff --git a/libs/api/domains/vehicles/src/lib/messages.ts b/libs/api/domains/vehicles/src/lib/messages.ts new file mode 100644 index 000000000000..2d3b82517ee0 --- /dev/null +++ b/libs/api/domains/vehicles/src/lib/messages.ts @@ -0,0 +1,83 @@ +import { defineMessages } from 'react-intl' + +export const m = defineMessages({ + tooManyPermno: { + id: 'api.bulk-vehicle-mileage:too-many-permno', + defaultMessage: 'Sama fastanúmer birtist oft í skjali', + }, + missingPermno: { + id: 'api.bulk-vehicle-mileage:missing-permno', + defaultMessage: 'Fastanúmer vantar', + }, + dateMissing: { + id: 'api.bulk-vehicle-mileage:date-missing', + defaultMessage: 'Dagsetning álesturs vantar', + }, + originMissing: { + id: 'api.bulk-vehicle-mileage:missing-origin', + defaultMessage: 'Uppruna álesturs vantar', + }, + mileageMissing: { + id: 'api.bulk-vehicle-mileage:missing-mileage', + defaultMessage: 'Álestur vantar', + }, + mileageTooLow: { + id: 'api.bulk-vehicle-mileage:mileage-too-low', + defaultMessage: 'Km staða getur ekki verið minna en 0', + }, + mileageLowerThanBefore: { + id: 'api.bulk-vehicle-mileage:mileage-lower-than-before', + defaultMessage: + 'Km staða álesturs getur ekki verið minni en síðasta gildi sem skráð hefur verið á ökutækið', + }, + originNotFound: { + id: 'api.bulk-vehicle-mileage:origin-not-found', + defaultMessage: 'Staðartegund í álestri finnst ekki', + }, + carNotFound: { + id: 'api.bulk-vehicle-mileage:car-not-found', + defaultMessage: 'Ökutæki finnst ekki', + }, + dateTooEarly: { + id: 'api.bulk-vehicle-mileage:date-too-early', + defaultMessage: 'Dagsetning færslu minni en nýjasta færsla á ökutæki', + }, + invalidUpdate: { + id: 'api.bulk-vehicle-mileage:invalid-update', + defaultMessage: 'Ekki má breyta færslu sem er ekki innan dagsins í dag', + }, + registerTooEarly: { + id: 'api.bulk-vehicle-mileage:register-too-early', + defaultMessage: + 'Villa við skráningu, ekki má skrá innan 30 daga frá síðustu færslu', + }, + forbiddenUpdate: { + id: 'api.bulk-vehicle-mileage:forbidden-update', + defaultMessage: 'Ekki má breyta færslu sem er ekki nýjasta færsla ökutækis', + }, + unauthorizedUpdater: { + id: 'api.bulk-vehicle-mileage:unauthorized-updater', + defaultMessage: + 'Tilkynnandi eða innsendur tilkynnandi er hvorki umráðamaður né eigandi ökutækis', + }, + invalidMileage: { + id: 'api.bulk-vehicle-mileage:invalid-mileage', + defaultMessage: 'Tegund álesturs ekki til', + }, + invalidDelete: { + id: 'api.bulk-vehicle-mileage:invalid-delete', + defaultMessage: 'Aðeins er leyfilegt að eyða nýjustu km skráningu', + }, + notFoundDelete: { + id: 'api.bulk-vehicle-mileage:not-found-delete', + defaultMessage: 'Færsla til að eyða finnst ekki', + }, + unnecessaryRegistration: { + id: 'api.bulk-vehicle-mileage:unnecessary-registration', + defaultMessage: 'Ökutæki krefst ekki aflesturs', + }, + tooHighMileage: { + id: 'api.bulk-vehicle-mileage:too-high-mileage', + defaultMessage: 'Km staða fer yfir hámark per dag', + }, +}) diff --git a/libs/api/domains/vehicles/src/lib/models/v3/bulkMileage/bulkMileageRegistrationRequestError.model.ts b/libs/api/domains/vehicles/src/lib/models/v3/bulkMileage/bulkMileageRegistrationRequestError.model.ts index a289df9b6cfa..f8f6bf80f1dc 100644 --- a/libs/api/domains/vehicles/src/lib/models/v3/bulkMileage/bulkMileageRegistrationRequestError.model.ts +++ b/libs/api/domains/vehicles/src/lib/models/v3/bulkMileage/bulkMileageRegistrationRequestError.model.ts @@ -1,4 +1,4 @@ -import { Field, ObjectType } from '@nestjs/graphql' +import { Field, Int, ObjectType } from '@nestjs/graphql' @ObjectType() export class VehiclesBulkMileageRegistrationRequestError { @@ -7,4 +7,10 @@ export class VehiclesBulkMileageRegistrationRequestError { @Field({ nullable: true }) message?: string + + @Field(() => Int, { nullable: true }) + warningSerialCode?: number + + @Field({ nullable: true }) + warningText?: string } diff --git a/libs/api/domains/vehicles/src/lib/resolvers/bulkMileage.resolver.ts b/libs/api/domains/vehicles/src/lib/resolvers/bulkMileage.resolver.ts index a551c3dc893a..f8c40cfdfa30 100644 --- a/libs/api/domains/vehicles/src/lib/resolvers/bulkMileage.resolver.ts +++ b/libs/api/domains/vehicles/src/lib/resolvers/bulkMileage.resolver.ts @@ -66,6 +66,7 @@ export class VehiclesBulkMileageResolver { ) { return this.bulkService.getBulkMileageRegistrationRequestOverview( user, + input.locale, input.guid, ) } diff --git a/libs/api/domains/vehicles/src/lib/services/bulkMileage.service.ts b/libs/api/domains/vehicles/src/lib/services/bulkMileage.service.ts index d5aec6f44140..f34392b199aa 100644 --- a/libs/api/domains/vehicles/src/lib/services/bulkMileage.service.ts +++ b/libs/api/domains/vehicles/src/lib/services/bulkMileage.service.ts @@ -7,6 +7,7 @@ import { AuthMiddleware } from '@island.is/auth-nest-tools' import type { Auth, User } from '@island.is/auth-nest-tools' import { PostVehicleBulkMileageInput } from '../dto/postBulkVehicleMileage.input' import { isDefined } from '@island.is/shared/utils' +import type { Locale } from '@island.is/shared/types' import { LOG_CATEGORY } from '../constants' import { LOGGER_PROVIDER, type Logger } from '@island.is/logging' import { VehiclesBulkMileageReadingResponse } from '../models/v3/bulkMileage/bulkMileageReadingResponse.model' @@ -14,11 +15,16 @@ import { VehiclesBulkMileageRegistrationJobHistory } from '../models/v3/bulkMile import { VehiclesBulkMileageRegistrationRequestStatus } from '../models/v3/bulkMileage/bulkMileageRegistrationRequestStatus.model' import { VehiclesBulkMileageRegistrationRequestOverview } from '../models/v3/bulkMileage/bulkMileageRegistrationRequestOverview.model' import { FetchError } from '@island.is/clients/middlewares' +import { IntlService } from '@island.is/cms-translations' +import { errorCodeMessageMap } from './errorCodes' + +const namespaces = ['api.bulk-vehicle-mileage'] @Injectable() export class BulkMileageService { constructor( private mileageReadingApi: MileageReadingApi, + private readonly intlService: IntlService, @Inject(LOGGER_PROVIDER) private readonly logger: Logger, ) {} @@ -59,7 +65,6 @@ export class BulkMileageService { return { requestId: res.guid, - errorMessage: res.errorMessage ?? undefined, } } catch (e) { const error: Error = e @@ -127,8 +132,10 @@ export class BulkMileageService { async getBulkMileageRegistrationRequestOverview( auth: User, + locale: Locale, input: GetbulkmileagereadingrequeststatusGuidGetRequest['guid'], ): Promise { + const { formatMessage } = await this.intlService.useIntl(namespaces, locale) const data = await this.getMileageWithAuth( auth, ).getbulkmileagereadingrequestdetailsGuidGet({ guid: input }) @@ -139,15 +146,25 @@ export class BulkMileageService { if (!d.guid || !d.permno) { return null } + return { guid: d.guid, vehicleId: d.permno, mileage: d.mileage ?? undefined, returnCode: d.returnCode ?? undefined, - errors: d.errors?.map((e) => ({ - code: e.errorCode ?? undefined, - message: e.errorText ?? undefined, - })), + errors: d.errors?.map((e) => { + const warningSerial = + e.warningSerial === -1 ? 999 : e.warningSerial + + return { + code: e.errorCode ?? undefined, + message: e.errorText ?? undefined, + warningSerialCode: e.warningSerial, + warningText: warningSerial + ? formatMessage(errorCodeMessageMap[warningSerial]) + : undefined, + } + }), } }) .filter(isDefined), diff --git a/libs/api/domains/vehicles/src/lib/services/errorCodes.ts b/libs/api/domains/vehicles/src/lib/services/errorCodes.ts new file mode 100644 index 000000000000..ba2f1423f82f --- /dev/null +++ b/libs/api/domains/vehicles/src/lib/services/errorCodes.ts @@ -0,0 +1,24 @@ +import { MessageDescriptor } from 'react-intl' +import { m } from '../../lib/messages' + +export const errorCodeMessageMap: Record = { + 999: m.tooManyPermno, //returned error code is -1, which cant be used to index. Transform to 999 + 3: m.missingPermno, + 4: m.dateMissing, + 5: m.originMissing, + 6: m.mileageMissing, + 7: m.mileageTooLow, + 8: m.mileageLowerThanBefore, + 9: m.originNotFound, + 10: m.carNotFound, + 11: m.dateTooEarly, + 12: m.invalidUpdate, + 13: m.registerTooEarly, + 14: m.forbiddenUpdate, + 15: m.unauthorizedUpdater, + 16: m.invalidMileage, + 17: m.invalidDelete, + 18: m.notFoundDelete, + 19: m.unnecessaryRegistration, + 20: m.tooHighMileage, +} diff --git a/libs/api/domains/vehicles/src/lib/services/vehicles.service.ts b/libs/api/domains/vehicles/src/lib/services/vehicles.service.ts index b573cdeec805..018749f96b3c 100644 --- a/libs/api/domains/vehicles/src/lib/services/vehicles.service.ts +++ b/libs/api/domains/vehicles/src/lib/services/vehicles.service.ts @@ -11,7 +11,6 @@ import { VehicleDtoListPagedResponse, PersidnoLookupResultDto, CurrentVehiclesWithMilageAndNextInspDtoListPagedResponse, - ApiResponse, } from '@island.is/clients/vehicles' import { CanregistermileagePermnoGetRequest, @@ -19,7 +18,6 @@ import { MileageReadingApi, MileageReadingDto, PostMileageReadingModel, - PutMileageReadingModel, RequiresmileageregistrationPermnoGetRequest, RootPostRequest, RootPutRequest, @@ -35,10 +33,7 @@ import { GetVehiclesForUserInput, GetVehiclesListV2Input, } from '../dto/getVehiclesForUserInput' -import { - VehicleMileageDetail, - VehicleMileageOverview, -} from '../models/getVehicleMileage.model' +import { VehicleMileageOverview } from '../models/getVehicleMileage.model' import isSameDay from 'date-fns/isSameDay' import { mileageDetailConstructor } from '../utils/helpers' import { FetchError, handle404 } from '@island.is/clients/middlewares' @@ -470,9 +465,11 @@ export class VehiclesService { throw new ForbiddenException(UNAUTHORIZED_OWNERSHIP_LOG) } - return this.getMileageWithAuth(auth).rootPut({ + const dtos = await this.getMileageWithAuth(auth).rootPut({ putMileageReadingModel: input, }) + + return dtos.length > 0 ? dtos[0] : null } async postMileageReadingV2( @@ -537,9 +534,10 @@ export class VehiclesService { } try { - return this.getMileageWithAuth(auth).rootPut({ + const dtos = await this.getMileageWithAuth(auth).rootPut({ putMileageReadingModel: input, }) + return dtos.length > 0 ? dtos[0] : null } catch (e) { if (e instanceof FetchError && (e.status === 400 || e.status === 429)) { const errorBody = e.body as UpdateResponseError diff --git a/libs/api/domains/vehicles/src/lib/vehicles.module.ts b/libs/api/domains/vehicles/src/lib/vehicles.module.ts index 3fcb00edafd3..86dbbc62cce4 100644 --- a/libs/api/domains/vehicles/src/lib/vehicles.module.ts +++ b/libs/api/domains/vehicles/src/lib/vehicles.module.ts @@ -11,6 +11,7 @@ import { FeatureFlagModule } from '@island.is/nest/feature-flags' import { BulkMileageService } from './services/bulkMileage.service' import { VehiclesV3Resolver } from './resolvers/vehicleV3.resolver' import { VehiclesBulkMileageResolver } from './resolvers/bulkMileage.resolver' +import { CmsTranslationsModule } from '@island.is/cms-translations' @Module({ providers: [ @@ -26,6 +27,7 @@ import { VehiclesBulkMileageResolver } from './resolvers/bulkMileage.resolver' VehiclesClientModule, VehiclesMileageClientModule, AuthModule, + CmsTranslationsModule, FeatureFlagModule, ], exports: [VehiclesService], diff --git a/libs/clients/vehicles-mileage/src/clientConfig.json b/libs/clients/vehicles-mileage/src/clientConfig.json index b934c4f3088e..1af507c8b7a0 100644 --- a/libs/clients/vehicles-mileage/src/clientConfig.json +++ b/libs/clients/vehicles-mileage/src/clientConfig.json @@ -2,13 +2,14 @@ "openapi": "3.0.1", "info": { "title": "SGS Rest API", - "description": "Mileage reading API developed in .Net8.0 - Release-6 : 20231122.2", + "description": "Mileage reading API developed in .Net8.0 - Release-21 : 20241105.1", "contact": { "name": "Samgöngustofa", "email": "tolvuhjalp@samgongustofa.is" }, "version": "1.0" }, + "servers": [{ "url": "/vehicle/mileagereading" }], "paths": { "/authenticate": { "post": { @@ -243,11 +244,14 @@ } }, "responses": { - "201": { + "200": { "description": "OK", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/MileageReadingDto" } + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/MileageReadingDto" } + } } } }, @@ -788,6 +792,11 @@ "description": "Error code", "nullable": true }, + "warningSerial": { + "type": "integer", + "description": "Warning serial", + "format": "int32" + }, "errorText": { "type": "string", "description": "Error text", @@ -850,11 +859,6 @@ "type": "string", "description": "Guid to check for status and results", "nullable": true - }, - "errorMessage": { - "type": "string", - "description": "Error message if any", - "nullable": true } }, "additionalProperties": false, diff --git a/libs/service-portal/assets/src/lib/messages.ts b/libs/service-portal/assets/src/lib/messages.ts index caef9991b01f..3e6a455f3bac 100644 --- a/libs/service-portal/assets/src/lib/messages.ts +++ b/libs/service-portal/assets/src/lib/messages.ts @@ -218,6 +218,11 @@ export const vehicleMessage = defineMessages({ id: 'sp.vehicles:not-found', defaultMessage: 'Ökutæki fannst ekki', }, + invalidFileType: { + id: 'sp.vehicles:invalid-file-type', + defaultMessage: + 'Ógild skráargerð. Einungis .xlsx og .csv skrár eru samþykktar', + }, infoNote: { id: 'sp.vehicles:detail-info-note', defaultMessage: @@ -981,6 +986,10 @@ export const vehicleMessage = defineMessages({ id: 'sp.vehicles:upload-failed', defaultMessage: 'Upphleðsla mistókst', }, + noDataInUploadedFile: { + id: 'sp.vehicles:no-data-in-uploaded-file', + defaultMessage: 'Upphleðsla mistókst. Engin gögn í skjali', + }, wrongFileType: { id: 'sp.vehicles:wrong-file-type', defaultMessage: 'Vitlaus skráartýpa. Skrá verður að vera .csv eða .xslx', @@ -989,6 +998,16 @@ export const vehicleMessage = defineMessages({ id: 'sp.vehicles:error-while-processing', defaultMessage: 'Villa við að meðhöndla skjal. Villur: ', }, + invalidPermNoColumn: { + id: 'sp.vehicles:invalid-perm-no-column', + defaultMessage: + 'Fastanúmersdálk vantar eða er skrifaður rangt. Dálkanafn þarf að vera eitt af eftirfarandi; "permno", "vehicleid", "bilnumer","okutaeki","fastanumer"', + }, + invalidMileageColumn: { + id: 'sp.vehicles:invalid-mileage-column', + defaultMessage: + 'Kílómetrastöðudálk vantar eða er skrifaður rangt. Dálkanafn þarf að vera eitt af eftirfarandi; "kilometrastada", "mileage", "odometer"', + }, downloadFailed: { id: 'sp.vehicles:download-failed', defaultMessage: 'Niðurhal mistókst', diff --git a/libs/service-portal/assets/src/screens/VehicleBulkMileage/VehicleBulkMileage.tsx b/libs/service-portal/assets/src/screens/VehicleBulkMileage/VehicleBulkMileage.tsx index 635218334b18..787ab421d3a7 100644 --- a/libs/service-portal/assets/src/screens/VehicleBulkMileage/VehicleBulkMileage.tsx +++ b/libs/service-portal/assets/src/screens/VehicleBulkMileage/VehicleBulkMileage.tsx @@ -3,8 +3,8 @@ import { useLocale, useNamespaces } from '@island.is/localization' import { m, SAMGONGUSTOFA_SLUG, - IntroHeader, LinkButton, + IntroWrapper, } from '@island.is/service-portal/core' import { vehicleMessage as messages, vehicleMessage } from '../../lib/messages' import * as styles from './VehicleBulkMileage.css' @@ -61,7 +61,7 @@ const VehicleBulkMileage = () => { return ( - @@ -83,44 +83,45 @@ const VehicleBulkMileage = () => { } serviceProviderSlug={SAMGONGUSTOFA_SLUG} serviceProviderTooltip={formatMessage(m.vehiclesTooltip)} - /> - - - - - - {error && !loading && } - {!error && ( - - )} + > + + + + + + {error && !loading && } + {!error && ( + + )} - {totalPages > 1 && ( - ( - - )} - /> - )} - + {totalPages > 1 && ( + ( + + )} + /> + )} + + ) diff --git a/libs/service-portal/assets/src/screens/VehicleBulkMileage/VehicleBulkMileageRow.tsx b/libs/service-portal/assets/src/screens/VehicleBulkMileage/VehicleBulkMileageRow.tsx index 6536795c32aa..93a18bbae7c5 100644 --- a/libs/service-portal/assets/src/screens/VehicleBulkMileage/VehicleBulkMileageRow.tsx +++ b/libs/service-portal/assets/src/screens/VehicleBulkMileage/VehicleBulkMileageRow.tsx @@ -8,7 +8,7 @@ import { useGetUsersMileageLazyQuery, } from './VehicleBulkMileage.generated' -import { useEffect, useState, useCallback } from 'react' +import { useEffect, useState, useCallback, useMemo } from 'react' import { ExpandRow, NestedFullTable, @@ -22,6 +22,7 @@ import { InputController } from '@island.is/shared/form-fields' import * as styles from './VehicleBulkMileage.css' import { displayWithUnit } from '../../utils/displayWithUnit' import { isReadDateToday } from '../../utils/readDate' +import { isDefined } from '@island.is/shared/utils' const ORIGIN_CODE = 'ISLAND.IS' @@ -210,6 +211,42 @@ export const VehicleBulkMileageRow = ({ vehicle }: Props) => { } }, [mileageData?.vehicleMileageDetails, vehicle.vehicleId]) + const nestedTable = useMemo(() => { + if (!data?.vehiclesMileageRegistrationHistory) { + return [[]] + } + const tableData: Array> = [[]] + if (data?.vehiclesMileageRegistrationHistory?.lastMileageRegistration) { + tableData.push([ + formatDate( + data.vehiclesMileageRegistrationHistory.lastMileageRegistration.date, + ), + data.vehiclesMileageRegistrationHistory.lastMileageRegistration + .originCode, + //'-', + displayWithUnit( + data.vehiclesMileageRegistrationHistory.lastMileageRegistration + .mileage, + 'km', + true, + ), + ]) + } + for (const mileageRegistration of data?.vehiclesMileageRegistrationHistory + ?.mileageRegistrationHistory ?? []) { + if (mileageRegistration) { + tableData.push([ + formatDate(mileageRegistration.date), + mileageRegistration.originCode, + //'-', + displayWithUnit(mileageRegistration.mileage, 'km', true), + ]) + } + } + + return tableData + }, [data?.vehiclesMileageRegistrationHistory]) + return ( { ]} loading={loading} emptyMessage={formatMessage(vehicleMessage.mileageHistoryNotFound)} - data={ - data?.vehiclesMileageRegistrationHistory?.mileageRegistrationHistory?.map( - (r) => [ - formatDate(r.date), - r.originCode, - //'-', - displayWithUnit(r.mileage, 'km', true), - ], - ) ?? [] - } + data={nestedTable} /> )} diff --git a/libs/service-portal/assets/src/screens/VehicleBulkMileageJobDetail/VehicleBulkMileageJobDetail.graphql b/libs/service-portal/assets/src/screens/VehicleBulkMileageJobDetail/VehicleBulkMileageJobDetail.graphql index 41047a57ba5c..d6c342f0a2b8 100644 --- a/libs/service-portal/assets/src/screens/VehicleBulkMileageJobDetail/VehicleBulkMileageJobDetail.graphql +++ b/libs/service-portal/assets/src/screens/VehicleBulkMileageJobDetail/VehicleBulkMileageJobDetail.graphql @@ -18,6 +18,8 @@ query getJobRegistrations($input: BulkVehicleMileageRequestOverviewInput!) { errors { code message + warningSerialCode + warningText } } } diff --git a/libs/service-portal/assets/src/screens/VehicleBulkMileageJobDetail/VehicleBulkMileageJobDetail.tsx b/libs/service-portal/assets/src/screens/VehicleBulkMileageJobDetail/VehicleBulkMileageJobDetail.tsx index 8b2bc2750962..a82691339e33 100644 --- a/libs/service-portal/assets/src/screens/VehicleBulkMileageJobDetail/VehicleBulkMileageJobDetail.tsx +++ b/libs/service-portal/assets/src/screens/VehicleBulkMileageJobDetail/VehicleBulkMileageJobDetail.tsx @@ -8,12 +8,12 @@ import { } from '@island.is/island-ui/core' import { useLocale, useNamespaces } from '@island.is/localization' import { - IntroHeader, SAMGONGUSTOFA_SLUG, m, EmptyTable, TableGrid, downloadFile, + IntroWrapper, } from '@island.is/service-portal/core' import { Problem } from '@island.is/react-spa/shared' import { VehiclesBulkMileageRegistrationRequestStatus } from '@island.is/api/schema' @@ -34,7 +34,7 @@ type UseParams = { const VehicleBulkMileageJobDetail = () => { useNamespaces('sp.vehicles') - const { formatMessage } = useLocale() + const { formatMessage, locale } = useLocale() const { id } = useParams() as UseParams const { data, loading, error, refetch, networkStatus } = @@ -57,6 +57,7 @@ const VehicleBulkMileageJobDetail = () => { notifyOnNetworkStatusChange: true, variables: { input: { + locale: locale, guid: id, }, }, @@ -89,7 +90,7 @@ const VehicleBulkMileageJobDetail = () => { } return [ erroredVehicle.vehicleId, - erroredVehicle.errors.map((j) => j.message).join(', '), + erroredVehicle.errors.map((j) => j.warningText).join(', '), ] }) .filter(isDefined) @@ -103,19 +104,18 @@ const VehicleBulkMileageJobDetail = () => { !(registrationNetworkStatus === NetworkStatus.refetch) return ( - - - {formatMessage(vehicleMessage.dataAboutJob)} -
- {formatMessage(vehicleMessage.refreshDataAboutJob)} - - } - serviceProviderSlug={SAMGONGUSTOFA_SLUG} - serviceProviderTooltip={formatMessage(m.vehiclesTooltip)} - > + + {formatMessage(vehicleMessage.dataAboutJob)} +
+ {formatMessage(vehicleMessage.refreshDataAboutJob)} + + } + serviceProviderSlug={SAMGONGUSTOFA_SLUG} + serviceProviderTooltip={formatMessage(m.vehiclesTooltip)} + buttonGroup={ -
+ } + > {!error && !loading && !jobsStatus && ( { {displayWithUnit(j.mileage, 'km', true)} - {(j.errors ?? []).map((j) => j.message).join(', ')} + {(j.errors ?? []) + .map((j) => j.warningText) + .join(', ')} )) @@ -268,7 +271,7 @@ const VehicleBulkMileageJobDetail = () => {
)} - + ) } diff --git a/libs/service-portal/assets/src/screens/VehicleBulkMileageJobOverview/VehicleBulkMileageJobOverview.tsx b/libs/service-portal/assets/src/screens/VehicleBulkMileageJobOverview/VehicleBulkMileageJobOverview.tsx index 648ef2116b7c..ae2b5f970c30 100644 --- a/libs/service-portal/assets/src/screens/VehicleBulkMileageJobOverview/VehicleBulkMileageJobOverview.tsx +++ b/libs/service-portal/assets/src/screens/VehicleBulkMileageJobOverview/VehicleBulkMileageJobOverview.tsx @@ -7,6 +7,7 @@ import { LinkButton, EmptyTable, formatDateWithTime, + IntroWrapper, } from '@island.is/service-portal/core' import { Problem } from '@island.is/react-spa/shared' import { useGetRequestsStatusQuery } from './VehicleBulkMileageJobOverview.generated' @@ -63,16 +64,18 @@ const VehicleBulkMileageUploadJobOverview = () => { const jobs: Array = data?.vehicleBulkMileageRegistrationJobHistory?.history ?? [] - const sortedJobs = jobs.length > 1 ? [...jobs] : [] - sortedJobs.sort((a, b) => sortJobs(a, b)) + const sortedJobs = [...jobs] + if (sortedJobs.length > 1) { + sortedJobs.sort((a, b) => sortJobs(a, b)) + } + return ( - - + {error && } {!error && ( @@ -141,7 +144,7 @@ const VehicleBulkMileageUploadJobOverview = () => { message={formatMessage(vehicleMessage.noJobsFound)} /> )} - + ) } diff --git a/libs/service-portal/assets/src/screens/VehicleBulkMileageUpload/VehicleBulkMileageUpload.tsx b/libs/service-portal/assets/src/screens/VehicleBulkMileageUpload/VehicleBulkMileageUpload.tsx index 54aa3ad49589..a822c80f359b 100644 --- a/libs/service-portal/assets/src/screens/VehicleBulkMileageUpload/VehicleBulkMileageUpload.tsx +++ b/libs/service-portal/assets/src/screens/VehicleBulkMileageUpload/VehicleBulkMileageUpload.tsx @@ -10,18 +10,18 @@ import { fileExtensionWhitelist } from '@island.is/island-ui/core/types' import { useLocale, useNamespaces } from '@island.is/localization' import { useEffect, useState } from 'react' import { FileRejection } from 'react-dropzone' +import { AssetsPaths } from '../../lib/paths' +import { useVehicleBulkMileagePostMutation } from './VehicleBulkMileageUpload.generated' +import { vehicleMessage } from '../../lib/messages' +import { parseFileToMileageRecord } from '../../utils/parseFileToMileage' import { - IntroHeader, + IntroWrapper, LinkButton, SAMGONGUSTOFA_SLUG, m, } from '@island.is/service-portal/core' -import { Problem } from '@island.is/react-spa/shared' -import { AssetsPaths } from '../../lib/paths' -import { useVehicleBulkMileagePostMutation } from './VehicleBulkMileageUpload.generated' import VehicleBulkMileageFileDownloader from '../VehicleBulkMileage/VehicleBulkMileageFileDownloader' -import { vehicleMessage } from '../../lib/messages' -import { parseFileToMileageRecord } from '../../utils/parseFileToMileage' +import { Problem } from '@island.is/react-spa/shared' const extensionToType = { [fileExtensionWhitelist['.csv']]: 'csv', @@ -54,37 +54,45 @@ const VehicleBulkMileageUpload = () => { }, [data?.vehicleBulkMileagePost?.requestId]) const postMileage = async (file: File, type: 'xlsx' | 'csv') => { - try { - const records = await parseFileToMileageRecord(file, type) - if (!records.length) { + const records = await parseFileToMileageRecord(file, type) + + if (!Array.isArray(records)) { + if (records.code === 1) { + setUploadErrorMessage(formatMessage(vehicleMessage.invalidPermNoColumn)) + } else if (records.code === 2) { + setUploadErrorMessage( + formatMessage(vehicleMessage.invalidMileageColumn), + ) + } else { setUploadErrorMessage(formatMessage(vehicleMessage.uploadFailed)) - return } - if (typeof records === 'string') { - setUploadErrorMessage(records) - return - } - vehicleBulkMileagePostMutation({ - variables: { - input: { - mileageData: records.map((r) => ({ - mileageNumber: r.mileage, - vehicleId: r.vehicleId, - })), - originCode: 'ISLAND.IS', - }, - }, - }) - } catch (error) { - setUploadErrorMessage( - `${formatMessage(vehicleMessage.errorWhileProcessing) + error.message} - `, - ) + return + } + + if (!records.length) { + setUploadErrorMessage(formatMessage(vehicleMessage.noDataInUploadedFile)) + return } + vehicleBulkMileagePostMutation({ + variables: { + input: { + mileageData: records.map((r) => ({ + mileageNumber: r.mileage, + vehicleId: r.vehicleId, + })), + originCode: 'ISLAND.IS', + }, + }, + }) } - const handleOnInputFileUploadError = (files: FileRejection[]) => - setUploadErrorMessage(files[0].errors[0].message) + const handleOnInputFileUploadError = (files: FileRejection[]) => { + if (files[0].errors[0].code === 'file-invalid-type') { + setUploadErrorMessage(formatMessage(vehicleMessage.invalidFileType)) + } else { + setUploadErrorMessage(files[0].errors[0].message) + } + } const handleOnInputFileUploadRemove = () => setUploadedFile(null) @@ -113,18 +121,17 @@ const VehicleBulkMileageUpload = () => { } return ( - - + - - + } + > {error && } {data?.vehicleBulkMileagePost?.errorMessage && !loading && !error && ( @@ -187,7 +194,7 @@ const VehicleBulkMileageUpload = () => { errorMessage={uploadErrorMessage ?? undefined} /> - + ) } diff --git a/libs/service-portal/assets/src/utils/parseFileToMileage.ts b/libs/service-portal/assets/src/utils/parseFileToMileage.ts index 7382ab57e315..1c76e4f19a1b 100644 --- a/libs/service-portal/assets/src/utils/parseFileToMileage.ts +++ b/libs/service-portal/assets/src/utils/parseFileToMileage.ts @@ -7,6 +7,11 @@ export interface MileageRecord { mileage: number } +export interface MileageError { + code: 1 | 2 + message: string +} + const vehicleIndexTitle = [ 'permno', 'vehicleid', @@ -16,10 +21,19 @@ const vehicleIndexTitle = [ ] const mileageIndexTitle = ['kilometrastada', 'mileage', 'odometer'] +export const errorMap: Record = { + 1: `Invalid vehicle column header. Must be one of the following: ${vehicleIndexTitle.join( + ', ', + )}`, + 2: `Invalid mileage column header. Must be one of the following: ${mileageIndexTitle.join( + ', ', + )}`, +} + export const parseFileToMileageRecord = async ( file: File, type: 'csv' | 'xlsx', -): Promise> => { +): Promise | MileageError> => { const parsedLines: Array> = await (type === 'csv' ? parseCsv(file) : parseXlsx(file)) @@ -28,28 +42,28 @@ export const parseFileToMileageRecord = async ( const vehicleIndex = header.findIndex((l) => vehicleIndexTitle.includes(l.toLowerCase()), ) + if (vehicleIndex < 0) { - throw new Error( - `Invalid vehicle column header. Must be one of the following: ${vehicleIndexTitle.join( - ', ', - )}`, - ) + return { + code: 1, + message: errorMap[1], + } } + const mileageIndex = header.findIndex((l) => mileageIndexTitle.includes(l.toLowerCase()), ) if (mileageIndex < 0) { - throw new Error( - `Invalid mileage column header. Must be one of the following: ${mileageIndexTitle.join( - ', ', - )}`, - ) + return { + code: 2, + message: errorMap[2], + } } const uploadedOdometerStatuses: Array = values .map((row) => { - const mileage = Number(row[mileageIndex]) + const mileage = Number(sanitizeNumber(row[mileageIndex])) if (Number.isNaN(mileage)) { return undefined } @@ -76,7 +90,6 @@ const parseCsv = async (file: File) => { accumulatedChunk += decoder.decode(res.value) } } - return parseCsvString(accumulatedChunk) } @@ -89,7 +102,6 @@ const parseXlsx = async (file: File) => { const jsonData = XLSX.utils.sheet_to_csv( parsedFile.Sheets[parsedFile.SheetNames[0]], { - strip: true, blankrows: false, }, ) @@ -105,13 +117,13 @@ const parseCsvString = (chunk: string): Promise => { const records: string[][] = [] const parser = parse({ - cast: true, - skipEmptyLines: true, delimiter: [';', ','], + skipLinesWithEmptyValues: true, + trim: true, }) parser.on('readable', () => { - let record + let record: Array while ((record = parser.read()) !== null) { records.push(record) } @@ -129,3 +141,5 @@ const parseCsvString = (chunk: string): Promise => { parser.end() }) } + +const sanitizeNumber = (n: string) => n.replace(new RegExp(/[.,]/g), '') From df859d4095d9253001186e68d2700af70caa3dd6 Mon Sep 17 00:00:00 2001 From: Kristofer Date: Tue, 12 Nov 2024 09:23:58 +0000 Subject: [PATCH 02/13] chore(j-s): Add initial delay for `judicial-system-web` startup probe (#16802) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add initial delay. * chore: charts update dirty files --------- Co-authored-by: andes-it Co-authored-by: Róberta Andersen Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- apps/judicial-system/web/infra/judicial-system-web.ts | 2 +- charts/judicial-system/values.dev.yaml | 2 +- charts/judicial-system/values.prod.yaml | 2 +- charts/judicial-system/values.staging.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/judicial-system/web/infra/judicial-system-web.ts b/apps/judicial-system/web/infra/judicial-system-web.ts index fa924baca658..8a6ac2430abf 100644 --- a/apps/judicial-system/web/infra/judicial-system-web.ts +++ b/apps/judicial-system/web/infra/judicial-system-web.ts @@ -21,7 +21,7 @@ export const serviceSetup = (services: { SUPPORT_EMAIL: '/k8s/judicial-system/SUPPORT_EMAIL', }) .liveness('/liveness') - .readiness('/readiness') + .readiness({ path: '/readiness', timeoutSeconds: 10 }) .resources({ limits: { cpu: '200m', diff --git a/charts/judicial-system/values.dev.yaml b/charts/judicial-system/values.dev.yaml index b87ac2b9294f..49f263495fd2 100644 --- a/charts/judicial-system/values.dev.yaml +++ b/charts/judicial-system/values.dev.yaml @@ -532,7 +532,7 @@ judicial-system-web: readiness: initialDelaySeconds: 3 path: '/readiness' - timeoutSeconds: 3 + timeoutSeconds: 10 hpa: scaling: metric: diff --git a/charts/judicial-system/values.prod.yaml b/charts/judicial-system/values.prod.yaml index f0a1db2678df..3d7760a9ba00 100644 --- a/charts/judicial-system/values.prod.yaml +++ b/charts/judicial-system/values.prod.yaml @@ -532,7 +532,7 @@ judicial-system-web: readiness: initialDelaySeconds: 3 path: '/readiness' - timeoutSeconds: 3 + timeoutSeconds: 10 hpa: scaling: metric: diff --git a/charts/judicial-system/values.staging.yaml b/charts/judicial-system/values.staging.yaml index e4a133f4ad7e..74f9f7dbeb28 100644 --- a/charts/judicial-system/values.staging.yaml +++ b/charts/judicial-system/values.staging.yaml @@ -532,7 +532,7 @@ judicial-system-web: readiness: initialDelaySeconds: 3 path: '/readiness' - timeoutSeconds: 3 + timeoutSeconds: 10 hpa: scaling: metric: From e4b23747d3be32c241c3156bd67385ef4705a32d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Baldur=20=C3=93li?= Date: Tue, 12 Nov 2024 10:28:56 +0000 Subject: [PATCH 03/13] feat(application-system): New application - Work Accident Notification (#16632) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial application creation * Continued work setting up application * Further work setting up work accident notification application * Work on company screen in application * skeleton work for page steps * mock data and further work on steps * Further development of work accident notificaion application * Creating a new client for slysaskraning * starting client setup, getting open-api from VER * Setting up client for slysaskraning * clientConfig testing removed * further progress of work accident notification * fixing broken component to not push broken code * Working on consistant data going back and forth in screens * MultiSelect states/answers setup, added most serious option. Missing validation if user chooses most serious and then removes that option from multiselect * multiselect work * minor fixes, adding attributes to data schema * adding attributes to dataschema, still incomplete in terms of refining, validaiton etc.. * dev readme, delete later * fixing some messeges and adding seeder script * multiselect finished * dev readme, delete later v2 * adding create account mockup and submitapplication ! * some changes * Working on multiselect screens in tilkynning vinnuslyss * removing comments, logs and addding a useEffect to setValue to formcontext on load * adding 2 new screens (typeOfInjury and injuredBodyParts), minor fixes for when a user removes options from list that was previously chosen as the most serious, minor comments added and removed * changes to submitapplication * starting to index starfsmadur and orsakir screens to allow for multiple employees * indexing for multiple employees, data schema update, moving announcement page to its own file * overview * adding indexing to ids otherwise we get graphql validation errors * overview company * commenting out atvinnugreinaflokkun, will remove once confirmed it should not be there * about accident * adding conditional radio field to verkkaup, fixing code for major and sub groups since they do not all have the same format, employmentStatus dataschema added and fixed, starfsgrein not auto filling correct on back button fixes (should look at again to clean up code) * adding add employees button * add employee button works * bunch of schema/required/validation added * doesnotrequireanswer added * zod schema additions, required on component that should be required, removed console.logs, added error messaging to pages * Fixing mount issue when going from employee 2 to employee 1 via back button * adding things to overview employees and few things to submit application * forgot to save * adding template name and institution * resolving conflicts * adding input values and some changes to submit app * submit and conclusion * first commit of delete functionality, some todo cleanup * remove log * select checkbox design * adding delete button to overview screen * feature flag added, mobile styling fixed in overview, data schema minor update * merge conflict * fixing config module after recent main changes * Chaning minor texts, adding README, deleting dev_readme * update messages * adding date check * fixing submit * merge conflict * fixing minors things from PR suggestions etc. * Using Locale type * fixing spacing on Select inputs and adding a placeholder * placeholder and message changes * fallback if individual for branch info * fixing errors * employee name in overview + placeholder for causeAndConsequences * removing default on Select * fixing back button and conclusion navigation step view * Fixing for PR comment, mostly error message translations etc.. * fixing null values in answers causing validation fails because missing nullable. Simplifying multiple calls to same getValues * fixing issues with multidropdown and answers * Adding missing contentfulId to institutionMapper * add requiredScope * import missing * adding pdf to final page * minor fixes from PR review * fixing types * forgot one type * PR comment fixes * moved payload * adding type * Remove fake sections * removing title for pages that have no section * Adding work accident client to infra/src/dsl and application-system/api/infra and generating values * Adding to apps/api/infra and running yarn charts * changing pdf (#16799) --------- Co-authored-by: berglindoma13 Co-authored-by: Sigrún Tinna Gissurardóttir Co-authored-by: Sigrún Tinna Gissurardóttir <39527334+sigruntg@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- apps/api/infra/api.ts | 2 + apps/api/src/app/app.module.ts | 2 + .../api/infra/application-system-api.ts | 2 + charts/islandis/values.dev.yaml | 2 + charts/islandis/values.prod.yaml | 2 + charts/islandis/values.staging.yaml | 2 + infra/src/dsl/xroad.ts | 11 + .../work-accident-notification.module.ts | 22 + .../work-accident-notification.service.ts | 119 ++ .../work-accident-notification.utils.ts | 119 ++ .../src/lib/modules/templates/index.ts | 4 + .../src/lib/templateLoaders.ts | 2 + .../aosh/work-accident-notification/.babelrc | 12 + .../work-accident-notification/.eslintrc.json | 18 + .../aosh/work-accident-notification/README.md | 47 + .../work-accident-notification/project.json | 12 + .../src/assets/Logo.tsx | 47 + .../src/assets/vinnueftirlitid.tsx | 45 + .../src/dataProviders/index.ts | 9 + .../src/fields/AccidentLocation/index.tsx | 122 ++ .../src/fields/AddEmployee/index.tsx | 79 ++ .../src/fields/CauseOfInjury/index.tsx | 44 + .../src/fields/CheckboxFieldCustom/index.tsx | 127 ++ .../src/fields/Circumstance/index.tsx | 38 + .../fields/Components/CausesAndEffects.tsx | 209 +++ .../fields/Components/MultiSelectDropdown.tsx | 78 ++ .../MultiSelectDropdownController.tsx | 142 +++ .../src/fields/Components/ReviewGroup.tsx | 67 + .../src/fields/Components/types.ts | 4 + .../src/fields/DeleteEmployee/index.tsx | 84 ++ .../src/fields/Deviation/index.tsx | 37 + .../fields/EmployeeStartTimeError/index.tsx | 57 + .../src/fields/InjuredBodyParts/index.tsx | 41 + .../src/fields/Occupation/index.tsx | 467 +++++++ .../fields/Overview/EmployeeAccordionItem.tsx | 96 ++ .../src/fields/Overview/index.tsx | 106 ++ .../src/fields/PdfOverview/PdfOverview.css.ts | 7 + .../src/fields/PdfOverview/index.tsx | 77 ++ .../src/fields/PdfOverview/pdfDocument.tsx | 162 +++ .../src/fields/TitleWithRemove/index.tsx | 35 + .../src/fields/TypeOfInjury/index.tsx | 37 + .../src/fields/index.ts | 14 + .../src/forms/Conclusion.ts | 12 + .../src/forms/Prerequisites.ts | 14 + .../src/forms/RepeatableSection/index.ts | 7 + .../AccidentSection/about.ts | 169 +++ .../AccidentSection/index.ts | 9 + .../AnnouncementSection/index.ts | 58 + .../CauseAndConsequencesSection/absence.ts | 49 + .../causeOfInjury.ts | 36 + .../circumstances.ts | 36 + .../CauseAndConsequencesSection/deviation.ts | 36 + .../CauseAndConsequencesSection/index.ts | 28 + .../injuredBodyParts.ts | 36 + .../typeOfInjury.ts | 36 + .../ConclusionSection/index.ts | 48 + .../EmployeeSection/employee.ts | 273 ++++ .../EmployeeSection/index.ts | 23 + .../InformationSection/companySection.ts | 220 ++++ .../InformationSection/index.ts | 11 + .../InformationSection/projectPurchase.ts | 74 ++ .../InformationSection/workhealth.ts | 39 + .../OverviewSection/index.ts | 51 + .../WorkAccidentNotificationForm/index.ts | 34 + .../prerequisitesSection.ts | 57 + .../work-accident-notification/src/index.ts | 7 + .../lib/WorkAccidentNotificationTemplate.ts | 181 +++ .../src/lib/constants.ts | 15 + .../src/lib/dataSchema.ts | 216 ++++ .../src/lib/messages/accident.ts | 128 ++ .../src/lib/messages/causeAndConsequences.ts | 185 +++ .../src/lib/messages/conclusion.ts | 28 + .../src/lib/messages/employee.ts | 159 +++ .../src/lib/messages/externalData.ts | 81 ++ .../src/lib/messages/index.ts | 9 + .../src/lib/messages/information.ts | 182 +++ .../src/lib/messages/overview.ts | 217 ++++ .../src/lib/messages/sections.ts | 111 ++ .../src/lib/messages/shared.ts | 53 + .../src/shared/constants.ts | 8 + .../src/utils/dateManipulation.ts | 77 ++ .../src/utils/formatDate.ts | 9 + .../src/utils/formatPhonenumber.ts | 6 + .../getAccidentInformationForOverview.ts | 55 + .../getCauseAndConsequencesForOverview.ts | 113 ++ .../utils/getCompanyInformationForOverview.ts | 61 + .../getEmployeeInformationForOverview.ts | 110 ++ .../src/utils/index.ts | 11 + .../src/utils/isCompany.ts | 7 + .../work-accident-notification/tsconfig.json | 17 + .../tsconfig.lib.json | 23 + .../types/src/lib/ApplicationTypes.ts | 5 + .../types/src/lib/InstitutionMapper.ts | 5 + .../data/add-work-accident-scope-to-client.ts | 8 + libs/clients/work-accident-ver/.babelrc | 10 + libs/clients/work-accident-ver/.eslintrc.json | 18 + libs/clients/work-accident-ver/README.md | 7 + libs/clients/work-accident-ver/jest.config.ts | 11 + libs/clients/work-accident-ver/project.json | 38 + .../work-accident-ver/src/clientConfig.json | 1126 +++++++++++++++++ libs/clients/work-accident-ver/src/index.ts | 4 + .../work-accident-ver/src/lib/providers.ts | 74 ++ .../src/lib/workAccident.config.ts | 23 + .../src/lib/workAccident.module.ts | 9 + .../src/lib/workAccident.service.ts | 42 + libs/clients/work-accident-ver/tsconfig.json | 16 + .../work-accident-ver/tsconfig.lib.json | 12 + .../work-accident-ver/tsconfig.spec.json | 20 + libs/feature-flags/src/lib/features.ts | 1 + .../core/src/lib/Select/Components/index.tsx | 29 + .../core/src/lib/Select/Select.css.ts | 36 + libs/island-ui/core/src/lib/Select/Select.tsx | 5 + .../core/src/lib/Select/Select.types.ts | 13 + tsconfig.base.json | 6 + 114 files changed, 7552 insertions(+) create mode 100644 libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.module.ts create mode 100644 libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.service.ts create mode 100644 libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.utils.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/.babelrc create mode 100644 libs/application/templates/aosh/work-accident-notification/.eslintrc.json create mode 100644 libs/application/templates/aosh/work-accident-notification/README.md create mode 100644 libs/application/templates/aosh/work-accident-notification/project.json create mode 100644 libs/application/templates/aosh/work-accident-notification/src/assets/Logo.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/assets/vinnueftirlitid.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/dataProviders/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/AccidentLocation/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/AddEmployee/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/CauseOfInjury/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/CheckboxFieldCustom/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/Circumstance/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/Components/CausesAndEffects.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/Components/MultiSelectDropdown.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/Components/MultiSelectDropdownController.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/Components/ReviewGroup.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/Components/types.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/DeleteEmployee/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/Deviation/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/EmployeeStartTimeError/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/InjuredBodyParts/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/Occupation/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/Overview/EmployeeAccordionItem.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/Overview/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/PdfOverview/PdfOverview.css.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/PdfOverview/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/PdfOverview/pdfDocument.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/TitleWithRemove/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/TypeOfInjury/index.tsx create mode 100644 libs/application/templates/aosh/work-accident-notification/src/fields/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/Conclusion.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/Prerequisites.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/RepeatableSection/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/AccidentSection/about.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/AccidentSection/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/AnnouncementSection/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/CauseAndConsequencesSection/absence.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/CauseAndConsequencesSection/causeOfInjury.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/CauseAndConsequencesSection/circumstances.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/CauseAndConsequencesSection/deviation.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/CauseAndConsequencesSection/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/CauseAndConsequencesSection/injuredBodyParts.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/CauseAndConsequencesSection/typeOfInjury.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/ConclusionSection/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/EmployeeSection/employee.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/EmployeeSection/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/InformationSection/companySection.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/InformationSection/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/InformationSection/projectPurchase.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/InformationSection/workhealth.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/OverviewSection/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/prerequisitesSection.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/WorkAccidentNotificationTemplate.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/constants.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/dataSchema.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/messages/accident.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/messages/causeAndConsequences.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/messages/conclusion.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/messages/employee.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/messages/externalData.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/messages/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/messages/information.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/messages/overview.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/messages/sections.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/lib/messages/shared.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/shared/constants.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/utils/dateManipulation.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/utils/formatDate.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/utils/formatPhonenumber.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/utils/getAccidentInformationForOverview.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/utils/getCauseAndConsequencesForOverview.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/utils/getCompanyInformationForOverview.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/utils/getEmployeeInformationForOverview.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/utils/index.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/src/utils/isCompany.ts create mode 100644 libs/application/templates/aosh/work-accident-notification/tsconfig.json create mode 100644 libs/application/templates/aosh/work-accident-notification/tsconfig.lib.json create mode 100644 libs/auth-api-lib/seeders/data/add-work-accident-scope-to-client.ts create mode 100644 libs/clients/work-accident-ver/.babelrc create mode 100644 libs/clients/work-accident-ver/.eslintrc.json create mode 100644 libs/clients/work-accident-ver/README.md create mode 100644 libs/clients/work-accident-ver/jest.config.ts create mode 100644 libs/clients/work-accident-ver/project.json create mode 100644 libs/clients/work-accident-ver/src/clientConfig.json create mode 100644 libs/clients/work-accident-ver/src/index.ts create mode 100644 libs/clients/work-accident-ver/src/lib/providers.ts create mode 100644 libs/clients/work-accident-ver/src/lib/workAccident.config.ts create mode 100644 libs/clients/work-accident-ver/src/lib/workAccident.module.ts create mode 100644 libs/clients/work-accident-ver/src/lib/workAccident.service.ts create mode 100644 libs/clients/work-accident-ver/tsconfig.json create mode 100644 libs/clients/work-accident-ver/tsconfig.lib.json create mode 100644 libs/clients/work-accident-ver/tsconfig.spec.json diff --git a/apps/api/infra/api.ts b/apps/api/infra/api.ts index f8d7e737d035..9e7ae515e497 100644 --- a/apps/api/infra/api.ts +++ b/apps/api/infra/api.ts @@ -49,6 +49,7 @@ import { Vehicles, VehicleServiceFjsV1, VehiclesMileage, + WorkAccidents, WorkMachines, } from '../../../infra/src/dsl/xroad' @@ -440,6 +441,7 @@ export const serviceSetup = (services: { Frigg, HealthDirectorateOrganDonation, HealthDirectorateVaccination, + WorkAccidents, ) .files({ filename: 'islyklar.p12', env: 'ISLYKILL_CERT' }) .ingress({ diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 97a8673797ad..7431d688223a 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -146,6 +146,7 @@ import { CmsTranslationsModule } from '@island.is/cms-translations' import { FileStorageConfig } from '@island.is/file-storage' import { AuditModule } from '@island.is/nest/audit' import { DocumentsClientV2Config } from '@island.is/clients/documents-v2' +import { WorkAccidentClientConfig } from '@island.is/clients/work-accident-ver' import { ConfigModule, @@ -432,6 +433,7 @@ const environment = getConfig CriminalRecordClientConfig, HealthInsuranceV2ClientConfig, UmbodsmadurSkuldaraClientConfig, + WorkAccidentClientConfig, ZendeskServiceConfig, emailModuleConfig, ], diff --git a/apps/application-system/api/infra/application-system-api.ts b/apps/application-system/api/infra/application-system-api.ts index d7e2dec8ba98..ce7360862365 100644 --- a/apps/application-system/api/infra/application-system-api.ts +++ b/apps/application-system/api/infra/application-system-api.ts @@ -36,6 +36,7 @@ import { Frigg, HealthDirectorateVaccination, HealthDirectorateOrganDonation, + WorkAccidents, NationalRegistryB2C, } from '../../../../infra/src/dsl/xroad' @@ -300,6 +301,7 @@ export const serviceSetup = (services: { Frigg, HealthDirectorateVaccination, HealthDirectorateOrganDonation, + WorkAccidents, ) .secrets({ NOVA_URL: '/k8s/application-system-api/NOVA_URL', diff --git a/charts/islandis/values.dev.yaml b/charts/islandis/values.dev.yaml index c623fa075f17..bfb3f1808c6d 100644 --- a/charts/islandis/values.dev.yaml +++ b/charts/islandis/values.dev.yaml @@ -409,6 +409,7 @@ api: XROAD_VEHICLE_SERVICE_FJS_V1_PATH: 'IS-DEV/GOV/10021/FJS-Public/VehicleServiceFJS_v1' XROAD_VMST_API_PATH: '/VMST-ParentalLeave-Protected/ParentalLeaveApplication-v1' XROAD_VMST_MEMBER_CODE: '10003' + XROAD_WORK_ACCIDENT_PATH: 'IS-DEV/GOV/10013/Vinnueftirlitid-Protected/slysaskraning-token' XROAD_WORK_MACHINE_LICENSE_PATH: 'IS-DEV/GOV/10013/Vinnueftirlitid-Protected/vinnuvelar-token' ZENDESK_CONTACT_FORM_SUBDOMAIN: 'stjanilofts' files: @@ -687,6 +688,7 @@ application-system-api: XROAD_VEHICLE_SERVICE_FJS_V1_PATH: 'IS-DEV/GOV/10021/FJS-Public/VehicleServiceFJS_v1' XROAD_VMST_API_PATH: '/VMST-ParentalLeave-Protected/ParentalLeaveApplication-v1' XROAD_VMST_MEMBER_CODE: '10003' + XROAD_WORK_ACCIDENT_PATH: 'IS-DEV/GOV/10013/Vinnueftirlitid-Protected/slysaskraning-token' XROAD_WORK_MACHINE_LICENSE_PATH: 'IS-DEV/GOV/10013/Vinnueftirlitid-Protected/vinnuvelar-token' files: - 'islyklar.p12' diff --git a/charts/islandis/values.prod.yaml b/charts/islandis/values.prod.yaml index 475d6bf4064f..3bc73c51e223 100644 --- a/charts/islandis/values.prod.yaml +++ b/charts/islandis/values.prod.yaml @@ -397,6 +397,7 @@ api: XROAD_VEHICLE_SERVICE_FJS_V1_PATH: 'IS/GOV/5402697509/FJS-Public/VehicleServiceFJS_v1' XROAD_VMST_API_PATH: '/VMST-ParentalLeave-Protected/ParentalLeaveApplication-v1' XROAD_VMST_MEMBER_CODE: '7005942039' + XROAD_WORK_ACCIDENT_PATH: 'IS/GOV/4201810439/Vinnueftirlitid-Protected/slysaskraning-token' XROAD_WORK_MACHINE_LICENSE_PATH: 'IS/GOV/4201810439/Vinnueftirlitid-Protected/vinnuvelar-token' ZENDESK_CONTACT_FORM_SUBDOMAIN: 'digitaliceland' files: @@ -675,6 +676,7 @@ application-system-api: XROAD_VEHICLE_SERVICE_FJS_V1_PATH: 'IS/GOV/5402697509/FJS-Public/VehicleServiceFJS_v1' XROAD_VMST_API_PATH: '/VMST-ParentalLeave-Protected/ParentalLeaveApplication-v1' XROAD_VMST_MEMBER_CODE: '7005942039' + XROAD_WORK_ACCIDENT_PATH: 'IS/GOV/4201810439/Vinnueftirlitid-Protected/slysaskraning-token' XROAD_WORK_MACHINE_LICENSE_PATH: 'IS/GOV/4201810439/Vinnueftirlitid-Protected/vinnuvelar-token' files: - 'islyklar.p12' diff --git a/charts/islandis/values.staging.yaml b/charts/islandis/values.staging.yaml index 402379a9766c..40fa4d62494b 100644 --- a/charts/islandis/values.staging.yaml +++ b/charts/islandis/values.staging.yaml @@ -409,6 +409,7 @@ api: XROAD_VEHICLE_SERVICE_FJS_V1_PATH: 'IS-TEST/GOV/10021/FJS-Public/VehicleServiceFJS_v1' XROAD_VMST_API_PATH: '/VMST-ParentalLeave-Protected/ParentalLeaveApplication-v1' XROAD_VMST_MEMBER_CODE: '7005942039' + XROAD_WORK_ACCIDENT_PATH: 'IS-TEST/GOV/4201810439/Vinnueftirlitid-Protected/slysaskraning-token' XROAD_WORK_MACHINE_LICENSE_PATH: 'IS-TEST/GOV/4201810439/Vinnueftirlitid-Protected/vinnuvelar-token' ZENDESK_CONTACT_FORM_SUBDOMAIN: 'digitaliceland' files: @@ -684,6 +685,7 @@ application-system-api: XROAD_VEHICLE_SERVICE_FJS_V1_PATH: 'IS-TEST/GOV/10021/FJS-Public/VehicleServiceFJS_v1' XROAD_VMST_API_PATH: '/VMST-ParentalLeave-Protected/ParentalLeaveApplication-v1' XROAD_VMST_MEMBER_CODE: '7005942039' + XROAD_WORK_ACCIDENT_PATH: 'IS-TEST/GOV/4201810439/Vinnueftirlitid-Protected/slysaskraning-token' XROAD_WORK_MACHINE_LICENSE_PATH: 'IS-TEST/GOV/4201810439/Vinnueftirlitid-Protected/vinnuvelar-token' files: - 'islyklar.p12' diff --git a/infra/src/dsl/xroad.ts b/infra/src/dsl/xroad.ts index 744e55362cbf..054994ed2b18 100644 --- a/infra/src/dsl/xroad.ts +++ b/infra/src/dsl/xroad.ts @@ -240,6 +240,17 @@ export const AdrAndMachine = new XroadConf({ }, }) +export const WorkAccidents = new XroadConf({ + env: { + XROAD_WORK_ACCIDENT_PATH: { + dev: 'IS-DEV/GOV/10013/Vinnueftirlitid-Protected/slysaskraning-token', + staging: + 'IS-TEST/GOV/4201810439/Vinnueftirlitid-Protected/slysaskraning-token', + prod: 'IS/GOV/4201810439/Vinnueftirlitid-Protected/slysaskraning-token', + }, + }, +}) + export const WorkMachines = new XroadConf({ env: { XROAD_WORK_MACHINE_LICENSE_PATH: { diff --git a/libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.module.ts b/libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.module.ts new file mode 100644 index 000000000000..01721028d473 --- /dev/null +++ b/libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.module.ts @@ -0,0 +1,22 @@ +import { Module } from '@nestjs/common' +import { SharedTemplateAPIModule } from '../../../shared' +import { WorkAccidentNotificationTemplateService } from './work-accident-notification.service' +import { + WorkAccidentClientConfig, + WorkAccidentClientModule, +} from '@island.is/clients/work-accident-ver' +import { ConfigModule } from '@nestjs/config' + +@Module({ + imports: [ + SharedTemplateAPIModule, + WorkAccidentClientModule, + ConfigModule.forRoot({ + isGlobal: true, + load: [WorkAccidentClientConfig], + }), + ], + providers: [WorkAccidentNotificationTemplateService], + exports: [WorkAccidentNotificationTemplateService], +}) +export class WorkAccidentNotificationTemplateModule {} diff --git a/libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.service.ts b/libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.service.ts new file mode 100644 index 000000000000..54839ce19a07 --- /dev/null +++ b/libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.service.ts @@ -0,0 +1,119 @@ +import { Inject, Injectable } from '@nestjs/common' +import { ApplicationTypes } from '@island.is/application/types' +import { BaseTemplateApiService } from '../../../base-template-api.service' + +import type { Logger } from '@island.is/logging' +import { LOGGER_PROVIDER } from '@island.is/logging' +import { TemplateApiModuleActionProps } from '../../../../types' +import { WorkAccidentNotification } from '@island.is/application/templates/aosh/work-accident-notification' +import { + DataDto, + WorkAccidentClientService, +} from '@island.is/clients/work-accident-ver' +import { + getDateAndTime, + getValueList, + mapVictimData, +} from './work-accident-notification.utils' +import { getValueViaPath } from '@island.is/application/core' +import { TemplateApiError } from '@island.is/nest/problem' + +@Injectable() +export class WorkAccidentNotificationTemplateService extends BaseTemplateApiService { + constructor( + @Inject(LOGGER_PROVIDER) private logger: Logger, + private readonly workAccidentClientService: WorkAccidentClientService, + ) { + super(ApplicationTypes.WORK_ACCIDENT_NOTIFICATION) + } + + async getInputOptions({ + currentUserLocale, + auth, + }: TemplateApiModuleActionProps): Promise { + const data = await this.workAccidentClientService + .getOptionsData(auth, currentUserLocale) + .catch(() => { + this.logger.warn( + '[work-accident-notification-service]: Error fetching data from AOSH', + ) + throw new TemplateApiError( + { + summary: + 'Ekki tókst að sækja gögn til VER, vinsamlegast reynið síðar', + title: 'Villa í umsókn', + }, + 400, + ) + }) + + return data + } + + async submitApplication({ + application, + auth, + }: TemplateApiModuleActionProps): Promise { + const answers = application.answers as unknown as WorkAccidentNotification + const payload = { + accidentForCreationDto: { + companySSN: answers.companyInformation.nationalId, + sizeOfEnterprise: parseInt( + answers.companyInformation.numberOfEmployees, + 10, + ), + nameOfBranchOrDepartment: + answers.companyInformation.nameOfBranch ?? + answers.companyInformation.name, + address: + answers.companyInformation.addressOfBranch ?? + answers.companyInformation.address, + postcode: + answers.companyInformation.postnumberOfBranch?.slice(0, 3) ?? + answers.companyInformation.postnumber.slice(0, 3), + workplaceHealthAndSafety: + answers.companyLaborProtection.workhealthAndSafetyOccupation?.map( + (code: string) => { + return parseInt(code, 10) + }, + ), + + buyersSSN: answers.projectPurchase.nationalId ?? '', + dateAndTimeOfAccident: getDateAndTime( + answers.accident.date, + answers.accident.time.slice(0, 2), + answers.accident.time.slice(2, 4), + ), + aoshCame: answers.accident.didAoshCome === 'yes', + policeCame: answers.accident.didPoliceCome === 'yes', + numberOfVictims: answers.employee.length, + municipalityWhereAccidentOccured: answers.accident.municipality, + specificLocationOfAccident: answers.accident.exactLocation, + detailedDescriptionOfAccident: answers.accident.wasDoing.concat( + '\n', + answers.accident.wentWrong, + '\n', + answers.accident.how, + ), + workingEnvironment: answers.accident.accidentLocation.value, + victims: answers.employee.map((employee, index) => { + return mapVictimData(employee, index, answers, application) + }), + userPhoneNumber: answers.companyInformation.phonenumber, + userEmail: answers.companyInformation.email, + }, + } + + await this.workAccidentClientService + .createAccident(auth, payload) + .catch(() => { + this.logger.warn( + '[work-accident-notification-service]: Error submitting application to AOSH', + ) + return { + success: false, + message: 'Villa í umsókn, ekki tókst að skila umsókn til VER.', + } + }) + } +} diff --git a/libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.utils.ts b/libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.utils.ts new file mode 100644 index 000000000000..ba4754bb45cd --- /dev/null +++ b/libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.utils.ts @@ -0,0 +1,119 @@ +import { getValueViaPath } from '@island.is/application/core' +import { WorkAccidentNotification } from '@island.is/application/templates/aosh/work-accident-notification' +import { + ApplicationWithAttachments, + FormValue, +} from '@island.is/application/types' + +export const getDateAndTime = ( + date: string, + hours: string, + minutes: string, +): Date => { + const finalDate = new Date(date) + finalDate.setHours( + parseInt(hours, 10), // hours + parseInt(minutes, 10), // minutes + ) + return finalDate +} + +export const getValueList = (answers: FormValue, answer: string) => { + const objectList = getValueViaPath(answers, answer) ?? {} + + return Object.values(objectList) + .map((values: { label: string; value: string }[]) => { + return values?.map(({ value }) => { + return value + }) + }) + .flat() +} + +export const mapVictimData = ( + employee: WorkAccidentNotification['employee'][0], + index: number, + answers: WorkAccidentNotification, + application: ApplicationWithAttachments, +) => { + const physicalActivities = getValueList( + application.answers, + `circumstances[${index}].physicalActivities`, + ) + const physicalActivitiesMostSerious = getValueViaPath( + application.answers, + `circumstances[${index}].physicalActivitiesMostSerious`, + ) + const workDeviations = getValueList( + application.answers, + `deviations[${index}].workDeviations`, + ) + const workDeviationsMostSerious = getValueViaPath( + application.answers, + `deviations[${index}].workDeviationsMostSerious`, + ) + const contactModeOfInjury = getValueList( + application.answers, + `causeOfInjury[${index}].contactModeOfInjury`, + ) + const contactModeOfInjuryMostSerious = getValueViaPath( + application.answers, + `causeOfInjury[${index}].contactModeOfInjuryMostSerious`, + ) + const partOfBodyInjured = getValueList( + application.answers, + `injuredBodyParts[${index}].partOfBodyInjured`, + ) + const partOfBodyInjuredMostSerious = getValueViaPath( + application.answers, + `injuredBodyParts[${index}].partOfBodyInjuredMostSerious`, + ) + const typeOfInjury = getValueList( + application.answers, + `typeOfInjury[${index}].typeOfInjury`, + ) + const typeOfInjuryMostSerious = getValueViaPath( + application.answers, + `typeOfInjury[${index}].typeOfInjuryMostSerious`, + ) + return { + victimsSSN: employee.nationalField.nationalId, + employmentStatusOfVictim: employee.employmentStatus + ? parseInt(employee.employmentStatus, 10) + : 0, + employmentAgencySSN: employee.tempEmploymentSSN ?? '', + startedEmploymentForCompany: new Date(employee.startDate), + lengthOfEmployment: employee.employmentTime + ? parseInt(employee.employmentTime, 10) + : 0, + percentageOfFullWorkTime: employee.employmentRate + ? parseInt(employee.employmentRate, 10) + : 0, + workhourArrangement: employee.workhourArrangement + ? parseInt(employee.workhourArrangement, 10) + : 0, + startOfWorkingDay: getDateAndTime( + employee.startOfWorkdayDate, + employee.startTime.slice(0, 2), + employee.startTime.slice(2, 4), + ), + workStation: employee.workstation ? parseInt(employee.workstation, 10) : 0, + victimsOccupation: employee.victimsOccupation.value, + absenceDueToAccident: answers.absence[index] + ? parseInt(answers.absence[index], 10) + : 0, + specificPhysicalActivities: physicalActivities, + specificPhysicalActivityMostSevere: + physicalActivitiesMostSerious ?? physicalActivities[0], + workDeviations: workDeviations, + workDeviationMostSevere: workDeviationsMostSerious ?? workDeviations[0], + contactModeOfInjuries: contactModeOfInjury, + contactModeOfInjuryMostSevere: + contactModeOfInjuryMostSerious ?? contactModeOfInjury[0], + partsOfBodyInjured: partOfBodyInjured, + partOfBodyInjuredMostSevere: + partOfBodyInjuredMostSerious ?? partOfBodyInjured[0], + typesOfInjury: typeOfInjury, + typeOfInjuryMostSevere: typeOfInjuryMostSerious ?? typeOfInjury[0], + } +} diff --git a/libs/application/template-api-modules/src/lib/modules/templates/index.ts b/libs/application/template-api-modules/src/lib/modules/templates/index.ts index b407059faf1f..26d046513f05 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/index.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/index.ts @@ -136,6 +136,8 @@ import { HealthInsuranceDeclarationModule } from './health-insurance-declaration import { HealthInsuranceDeclarationService } from './health-insurance-declaration/health-insurance-declaration.service' import { NewPrimarySchoolModule } from './new-primary-school/new-primary-school.module' import { NewPrimarySchoolService } from './new-primary-school/new-primary-school.service' +import { WorkAccidentNotificationTemplateModule } from './aosh/work-accident-notification/work-accident-notification.module' +import { WorkAccidentNotificationTemplateService } from './aosh/work-accident-notification/work-accident-notification.service' import { IdCardModule } from './id-card/id-card.module' import { IdCardService } from './id-card/id-card.service' import { ParliamentaryListCreationModule } from './signature-collection/parliamentary-list-creation/parliamentary-list-creation.module' @@ -211,6 +213,7 @@ export const modules = [ IdCardModule, HealthInsuranceDeclarationModule, NewPrimarySchoolModule, + WorkAccidentNotificationTemplateModule, ParliamentaryListCreationModule, ParliamentaryListSigningModule, ParentalLeaveModule, @@ -288,6 +291,7 @@ export const services = [ IdCardService, HealthInsuranceDeclarationService, NewPrimarySchoolService, + WorkAccidentNotificationTemplateService, ParliamentaryListCreationService, ParliamentaryListSigningService, ] diff --git a/libs/application/template-loader/src/lib/templateLoaders.ts b/libs/application/template-loader/src/lib/templateLoaders.ts index efdb9cb6f2ff..e882788887f5 100644 --- a/libs/application/template-loader/src/lib/templateLoaders.ts +++ b/libs/application/template-loader/src/lib/templateLoaders.ts @@ -197,6 +197,8 @@ const templates: Record Promise> = { import('@island.is/application/templates/aosh/street-registration'), [ApplicationTypes.REQUEST_INSPECTION_FOR_MACHINE]: () => import('@island.is/application/templates/aosh/request-for-inspection'), + [ApplicationTypes.WORK_ACCIDENT_NOTIFICATION]: () => + import('@island.is/application/templates/aosh/work-accident-notification'), [ApplicationTypes.ID_CARD]: () => import('@island.is/application/templates/id-card'), [ApplicationTypes.HEALTH_INSURANCE_DECLARATION]: () => diff --git a/libs/application/templates/aosh/work-accident-notification/.babelrc b/libs/application/templates/aosh/work-accident-notification/.babelrc new file mode 100644 index 000000000000..1ea870ead410 --- /dev/null +++ b/libs/application/templates/aosh/work-accident-notification/.babelrc @@ -0,0 +1,12 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [] +} diff --git a/libs/application/templates/aosh/work-accident-notification/.eslintrc.json b/libs/application/templates/aosh/work-accident-notification/.eslintrc.json new file mode 100644 index 000000000000..1ac7686355e0 --- /dev/null +++ b/libs/application/templates/aosh/work-accident-notification/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["plugin:@nx/react", "../../../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/application/templates/aosh/work-accident-notification/README.md b/libs/application/templates/aosh/work-accident-notification/README.md new file mode 100644 index 000000000000..f97d8ad8b3fd --- /dev/null +++ b/libs/application/templates/aosh/work-accident-notification/README.md @@ -0,0 +1,47 @@ +# Work Accident Notification application for The Administration of Occupational Safety and Health + +### Description + +The Work Accident Notification application allows both individual users and users with company delegations to submit accident reports. Individual users may only submit reports for their sole proprietorships, while company submissions require an assigned delegation. The application flow is nearly identical for both user types, with only minor variations in input fields based on the user’s role. + +### URLs + +- [Local](http://localhost:4242/umsoknir/tilkynning-um-vinnuslys) +- [Dev](https://beta.dev01.devland.is/umsoknir/tilkynning-um-vinnuslys) +- [Production](https://island.is/umsoknir/tilkynning-um-vinnuslys) + +### Clients and template-api-modules + +- [Client]('https://github.com/island-is/island.is/tree/main/libs/clients/work-accident-ver/src/lib/workAccident.service.ts') +- [Template-api-module]('https://github.com/island-is/island.is/blob/main/libs/application/template-api-modules/src/lib/modules/templates/aosh/work-accident-notification/work-accident-notification.service.ts') + +### States + +#### Prerequisite + +Data fetching from National Registry, User profile and The Administration of Occupational Safety and Health + +#### Draft + +In the Draft state, users input essential information for the accident report. This includes details about the company involved, specifics of the accident, and information on all injured employees. After entering this data, users can review an overview page, providing a chance to verify all inputs before final submission. + +#### Completed + +User recieves confirmation that reports has been successfully submitted and a PDF overview of the report + +### Localisation + +All localisation can be found on Contentful. + +- [Work Accident Notification translation]('https://app.contentful.com/spaces/8k0h54kbe6bj/entries/aosh.wan.application') +- [Application system translations](https://app.contentful.com/spaces/8k0h54kbe6bj/entries/application.system) + +### Test users + +- **Gervimaður Færeyjar 010130-2399 and 65°ARKTIC ehf delegation** + +### Codeowners + +- [Origo]('https://github.com/orgs/island-is/teams/origo') + - [Baldur Óli]('https://github.com/Ballioli') + - [Sigrún Tinna]('https://github.com/sigruntg') diff --git a/libs/application/templates/aosh/work-accident-notification/project.json b/libs/application/templates/aosh/work-accident-notification/project.json new file mode 100644 index 000000000000..ab889cfaf462 --- /dev/null +++ b/libs/application/templates/aosh/work-accident-notification/project.json @@ -0,0 +1,12 @@ +{ + "name": "application-templates-aosh-work-accident-notification", + "$schema": "../../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/application/templates/aosh/work-accident-notification/src", + "projectType": "library", + "tags": ["scope:application-system", "lib:application-system"], + "targets": { + "lint": { + "executor": "@nx/eslint:lint" + } + } +} diff --git a/libs/application/templates/aosh/work-accident-notification/src/assets/Logo.tsx b/libs/application/templates/aosh/work-accident-notification/src/assets/Logo.tsx new file mode 100644 index 000000000000..f22e281c69a9 --- /dev/null +++ b/libs/application/templates/aosh/work-accident-notification/src/assets/Logo.tsx @@ -0,0 +1,47 @@ +import React, { FC } from 'react' + +export const Logo: FC> = () => ( + + + + + + + + + + +) diff --git a/libs/application/templates/aosh/work-accident-notification/src/assets/vinnueftirlitid.tsx b/libs/application/templates/aosh/work-accident-notification/src/assets/vinnueftirlitid.tsx new file mode 100644 index 000000000000..339cb76fc45b --- /dev/null +++ b/libs/application/templates/aosh/work-accident-notification/src/assets/vinnueftirlitid.tsx @@ -0,0 +1,45 @@ +import { Svg, G, Path, Rect, Circle } from '@react-pdf/renderer' +import React, { FC } from 'react' + +export const Vinnueftirlitid: FC> = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +) diff --git a/libs/application/templates/aosh/work-accident-notification/src/dataProviders/index.ts b/libs/application/templates/aosh/work-accident-notification/src/dataProviders/index.ts new file mode 100644 index 000000000000..e1200811a96e --- /dev/null +++ b/libs/application/templates/aosh/work-accident-notification/src/dataProviders/index.ts @@ -0,0 +1,9 @@ +import { defineTemplateApi } from '@island.is/application/types' +import { ApiActions } from '../shared/constants' + +export { IdentityApi, UserProfileApi } from '@island.is/application/types' + +export const getAoshInputOptionsApi = defineTemplateApi({ + action: ApiActions.getInputOptions, + externalDataId: 'aoshData', +}) diff --git a/libs/application/templates/aosh/work-accident-notification/src/fields/AccidentLocation/index.tsx b/libs/application/templates/aosh/work-accident-notification/src/fields/AccidentLocation/index.tsx new file mode 100644 index 000000000000..df31e4cfa436 --- /dev/null +++ b/libs/application/templates/aosh/work-accident-notification/src/fields/AccidentLocation/index.tsx @@ -0,0 +1,122 @@ +import { FieldBaseProps } from '@island.is/application/types' +import { FC, useEffect, useState } from 'react' +import { + Box, + Checkbox, + GridColumn, + GridRow, + Select, +} from '@island.is/island-ui/core' +import { getValueViaPath } from '@island.is/application/core' +import { Controller, useFormContext } from 'react-hook-form' +import { accident } from '../../lib/messages' +import { useLocale } from '@island.is/localization' +import { WorkingEnvironmentDto } from '@island.is/clients/work-accident-ver' +import { WorkAccidentNotification } from '../../lib/dataSchema' + +type Option = { + value: string + label: string +} + +export const AccidentLocation: FC> = ( + props, +) => { + const { application } = props + const answers = application.answers as WorkAccidentNotification + const { setValue } = useFormContext() + const { formatMessage } = useLocale() + const workingEnvironment = + getValueViaPath( + application.externalData, + 'aoshData.data.workingEnvironment', + ) ?? [] + const majorGroups = workingEnvironment.filter((group) => !group.validToSelect) + + const minorGroups = workingEnvironment.filter((group) => group.validToSelect) + const [selectedMajorGroup, setSelectedMajorGroup] = useState