diff --git a/libs/api/domains/official-journal-of-iceland-application/src/lib/ojoiApplication.resolver.ts b/libs/api/domains/official-journal-of-iceland-application/src/lib/ojoiApplication.resolver.ts index 9ea5f38765d8..24806165906d 100644 --- a/libs/api/domains/official-journal-of-iceland-application/src/lib/ojoiApplication.resolver.ts +++ b/libs/api/domains/official-journal-of-iceland-application/src/lib/ojoiApplication.resolver.ts @@ -23,6 +23,8 @@ import { GetApplicationAttachmentInput } from '../models/getApplicationAttachmen import { GetApplicationAttachmentsResponse } from '../models/getApplicationAttachments.response' import { DeleteApplicationAttachmentInput } from '../models/deleteApplicationAttachment.input' import type { User } from '@island.is/auth-nest-tools' +import { GetUserInvolvedPartiesResponse } from '../models/getUserInvolvedParties.response' +import { GetUserInvolvedPartiesInput } from '../models/getUserInvolvedParties.input' @Scopes(ApiScope.internal) @UseGuards(IdsUserGuard, ScopesGuard) @@ -110,4 +112,15 @@ export class OfficialJournalOfIcelandApplicationResolver { ) { return this.ojoiApplicationService.deleteApplicationAttachment(input, user) } + + @Query(() => GetUserInvolvedPartiesResponse, { + name: 'officialJournalOfIcelandApplicationGetUserInvolvedParties', + }) + getUserInvolvedParties( + @Args('input', { type: () => GetUserInvolvedPartiesInput }) + input: GetUserInvolvedPartiesInput, + @CurrentUser() user: User, + ) { + return this.ojoiApplicationService.getUserInvolvedParties(input, user) + } } diff --git a/libs/api/domains/official-journal-of-iceland-application/src/lib/ojoiApplication.service.ts b/libs/api/domains/official-journal-of-iceland-application/src/lib/ojoiApplication.service.ts index 89b074ee1eae..3e445003a633 100644 --- a/libs/api/domains/official-journal-of-iceland-application/src/lib/ojoiApplication.service.ts +++ b/libs/api/domains/official-journal-of-iceland-application/src/lib/ojoiApplication.service.ts @@ -17,6 +17,7 @@ import { DeleteApplicationAttachmentInput } from '../models/deleteApplicationAtt import { LOGGER_PROVIDER } from '@island.is/logging' import type { Logger } from '@island.is/logging' import { User } from '@island.is/auth-nest-tools' +import { GetUserInvolvedPartiesInput } from '../models/getUserInvolvedParties.input' const LOG_CATEGORY = 'official-journal-of-iceland-application' @@ -166,4 +167,13 @@ export class OfficialJournalOfIcelandApplicationService { return { success: false } } } + + async getUserInvolvedParties(input: GetUserInvolvedPartiesInput, user: User) { + return this.ojoiApplicationService.getUserInvolvedParties( + { + id: input.applicationId, + }, + user, + ) + } } diff --git a/libs/api/domains/official-journal-of-iceland-application/src/models/getUserInvolvedParties.input.ts b/libs/api/domains/official-journal-of-iceland-application/src/models/getUserInvolvedParties.input.ts new file mode 100644 index 000000000000..9f045441743f --- /dev/null +++ b/libs/api/domains/official-journal-of-iceland-application/src/models/getUserInvolvedParties.input.ts @@ -0,0 +1,7 @@ +import { Field, ID, InputType } from '@nestjs/graphql' + +@InputType('GetUserInvolvedPartiesInput') +export class GetUserInvolvedPartiesInput { + @Field(() => ID) + applicationId!: string +} diff --git a/libs/api/domains/official-journal-of-iceland-application/src/models/getUserInvolvedParties.response.ts b/libs/api/domains/official-journal-of-iceland-application/src/models/getUserInvolvedParties.response.ts new file mode 100644 index 000000000000..73a2f1b29386 --- /dev/null +++ b/libs/api/domains/official-journal-of-iceland-application/src/models/getUserInvolvedParties.response.ts @@ -0,0 +1,19 @@ +import { Field, ObjectType } from '@nestjs/graphql' + +@ObjectType('OfficialJournalOfIcelandApplicationGetUserInvolvedParty') +export class InvolvededParty { + @Field({ description: 'The id of the involved party' }) + id!: string + + @Field({ description: 'The title of the involved party' }) + title!: string + + @Field({ description: 'The slug of the involved party' }) + slug!: string +} + +@ObjectType('OfficialJournalOfIcelandApplicationGetUserInvolvedPartiesResponse') +export class GetUserInvolvedPartiesResponse { + @Field(() => [InvolvededParty]) + involvedParties!: InvolvededParty[] +} diff --git a/libs/application/templates/official-journal-of-iceland/src/components/form/FormScreen.tsx b/libs/application/templates/official-journal-of-iceland/src/components/form/FormScreen.tsx index 4baca4510fed..e9df089c0bb3 100644 --- a/libs/application/templates/official-journal-of-iceland/src/components/form/FormScreen.tsx +++ b/libs/application/templates/official-journal-of-iceland/src/components/form/FormScreen.tsx @@ -2,11 +2,13 @@ import { AlertMessage, AlertMessageProps, Box, + SkeletonLoader, Text, } from '@island.is/island-ui/core' import * as styles from './FormScreen.css' import { useLocale } from '@island.is/localization' import { general } from '../../lib/messages' +import { OJOI_INPUT_HEIGHT } from '../../lib/constants' type WarningProps = { type?: AlertMessageProps['type'] @@ -20,6 +22,7 @@ type Props = { button?: React.ReactNode warning?: WarningProps children?: React.ReactNode + loading?: boolean } export const FormScreen = ({ @@ -28,6 +31,7 @@ export const FormScreen = ({ button, children, warning, + loading, }: Props) => { const { formatMessage } = useLocale() @@ -61,7 +65,16 @@ export const FormScreen = ({ )} - {children} + {loading ? ( + + ) : ( + {children} + )} ) } diff --git a/libs/application/templates/official-journal-of-iceland/src/forms/Requirements.ts b/libs/application/templates/official-journal-of-iceland/src/forms/Requirements.ts index cd147fc658f4..eb13107c7e93 100644 --- a/libs/application/templates/official-journal-of-iceland/src/forms/Requirements.ts +++ b/libs/application/templates/official-journal-of-iceland/src/forms/Requirements.ts @@ -16,6 +16,7 @@ import { preview, publishing, summary, + involvedParty, } from '../lib/messages' export const Requirements: Form = buildForm({ id: 'OfficialJournalOfIcelandApplication', @@ -35,8 +36,25 @@ export const Requirements: Form = buildForm({ title: '', component: 'RequirementsScreen', }), + ], + }), + ], + }), + buildSection({ + id: Routes.INVOLVED_PARTY, + title: involvedParty.general.section, + children: [ + buildMultiField({ + id: Routes.INVOLVED_PARTY, + title: '', + children: [ + buildCustomField({ + id: 'involvedParty', + title: '', + component: 'InvolvedPartyScreen', + }), buildSubmitField({ - id: 'toDraft', + id: 'toComments', title: '', refetchApplicationAfterSubmit: true, actions: [ diff --git a/libs/application/templates/official-journal-of-iceland/src/graphql/queries.ts b/libs/application/templates/official-journal-of-iceland/src/graphql/queries.ts index 62a83187a4d0..983c447c0cef 100644 --- a/libs/application/templates/official-journal-of-iceland/src/graphql/queries.ts +++ b/libs/application/templates/official-journal-of-iceland/src/graphql/queries.ts @@ -190,6 +190,18 @@ export const DEPARTMENTS_QUERY = gql` } ` +export const INVOLVED_PARTIES_QUERY = gql` + query InvolvedParties($input: GetUserInvolvedPartiesInput!) { + officialJournalOfIcelandApplicationGetUserInvolvedParties(input: $input) { + involvedParties { + id + title + slug + } + } + } +` + export const CATEGORIES_QUERY = gql` query AdvertCategories($params: OfficialJournalOfIcelandQueryInput!) { officialJournalOfIcelandCategories(params: $params) { diff --git a/libs/application/templates/official-journal-of-iceland/src/hooks/useInvolvedParties.ts b/libs/application/templates/official-journal-of-iceland/src/hooks/useInvolvedParties.ts new file mode 100644 index 000000000000..fa08402685bd --- /dev/null +++ b/libs/application/templates/official-journal-of-iceland/src/hooks/useInvolvedParties.ts @@ -0,0 +1,45 @@ +import { useQuery } from '@apollo/client' +import { OfficialJournalOfIcelandApplicationGetUserInvolvedPartiesResponse } from '@island.is/api/schema' +import { INVOLVED_PARTIES_QUERY } from '../graphql/queries' + +type Props = { + applicationId?: string + onComplete?: (data: InvolvedPartiesResponse) => void + onError?: (error: Error) => void +} + +type InvolvedPartiesResponse = { + officialJournalOfIcelandApplicationGetUserInvolvedParties: OfficialJournalOfIcelandApplicationGetUserInvolvedPartiesResponse +} +export const useInvolvedParties = ({ + applicationId, + onComplete, + onError, +}: Props) => { + const { data, loading, error } = useQuery( + INVOLVED_PARTIES_QUERY, + { + skip: !applicationId, + fetchPolicy: 'no-cache', + variables: { + input: { + applicationId: applicationId, + }, + }, + onCompleted: (data) => { + onComplete && onComplete(data) + }, + onError: (error) => { + onError && onError(error) + }, + }, + ) + + return { + involvedParties: + data?.officialJournalOfIcelandApplicationGetUserInvolvedParties + .involvedParties, + loading, + error, + } +} diff --git a/libs/application/templates/official-journal-of-iceland/src/lib/constants.ts b/libs/application/templates/official-journal-of-iceland/src/lib/constants.ts index 4ee1ecaaf486..a5710590e5ce 100644 --- a/libs/application/templates/official-journal-of-iceland/src/lib/constants.ts +++ b/libs/application/templates/official-journal-of-iceland/src/lib/constants.ts @@ -24,6 +24,7 @@ export const MINIMUM_WEEKDAYS = 10 export enum Routes { REQUIREMENTS = 'requirements', + INVOLVED_PARTY = 'involvedParty', COMMENTS = 'comments', ADVERT = 'advert', SIGNATURE = 'signature', diff --git a/libs/application/templates/official-journal-of-iceland/src/lib/messages/index.ts b/libs/application/templates/official-journal-of-iceland/src/lib/messages/index.ts index 125c0744b8c7..8e65f42869ce 100644 --- a/libs/application/templates/official-journal-of-iceland/src/lib/messages/index.ts +++ b/libs/application/templates/official-journal-of-iceland/src/lib/messages/index.ts @@ -11,3 +11,4 @@ export * from './publishing' export * from './summary' export * from './signatures' export * from './comments' +export * from './involved-parties' diff --git a/libs/application/templates/official-journal-of-iceland/src/lib/messages/involved-parties.ts b/libs/application/templates/official-journal-of-iceland/src/lib/messages/involved-parties.ts new file mode 100644 index 000000000000..373026a6e22b --- /dev/null +++ b/libs/application/templates/official-journal-of-iceland/src/lib/messages/involved-parties.ts @@ -0,0 +1,56 @@ +import { defineMessages } from 'react-intl' + +export const involvedParty = { + general: defineMessages({ + title: { + id: 'ojoi.application:original.general.title', + defaultMessage: 'Stofnun ', + description: 'Title of the involved party screen', + }, + intro: { + id: 'ojoi.application:original.general.intro', + defaultMessage: + 'Hér getur þú valið stofnun sem þú vilt tengja við umsóknina þína.', + description: 'Intro of the involved party form', + }, + section: { + id: 'ojoi.application:original.general.section', + defaultMessage: 'Stofnanir', + description: 'Title of the involved party section', + }, + }), + inputs: { + select: defineMessages({ + placeholder: { + id: 'ojoi.application:original.inputs.select.placeholder', + defaultMessage: 'Veldu stofnun', + description: 'Placeholder for the select input', + }, + }), + }, + + errors: defineMessages({ + title: { + id: 'ojoi.application:original.error.title', + defaultMessage: 'Þú hefur ekki aðgang', + description: 'Title of the error message', + }, + message: { + id: 'ojoi.application:original.error.message', + defaultMessage: + 'Ekki tókst að sækja stofnanir fyrir aðganginn þinn, ef þú telur þig eiga að hafa aðgang, vinsamlegast hafðu samband við ritstjóra Stjórnartíðnda.', + description: 'Error message', + }, + noDataTitle: { + id: 'ojoi.application:original.error.noDataTitle', + defaultMessage: 'Engar stofnanir', + description: 'Title of the no data message', + }, + noDataMessage: { + id: 'ojoi.application:original.error.noDataMessage', + defaultMessage: + 'Notandinn er ekki tengdur neinum stofnunum, vinsamlegast hafðu samband við ritstjóra Stjórnartíðnda.', + description: 'No data message', + }, + }), +} diff --git a/libs/application/templates/official-journal-of-iceland/src/lib/types.ts b/libs/application/templates/official-journal-of-iceland/src/lib/types.ts index ab0c6d2a68a3..1d4a4ad4cbed 100644 --- a/libs/application/templates/official-journal-of-iceland/src/lib/types.ts +++ b/libs/application/templates/official-journal-of-iceland/src/lib/types.ts @@ -19,6 +19,7 @@ export const InputFields = { categories: 'advert.categories', channels: 'advert.channels', message: 'advert.message', + involvedPartyId: 'advert.involvedPartyId', }, [Routes.SIGNATURE]: { regular: 'signatures.regular', diff --git a/libs/application/templates/official-journal-of-iceland/src/screens/InvolvedPartyScreen.tsx b/libs/application/templates/official-journal-of-iceland/src/screens/InvolvedPartyScreen.tsx new file mode 100644 index 000000000000..055c69fe598c --- /dev/null +++ b/libs/application/templates/official-journal-of-iceland/src/screens/InvolvedPartyScreen.tsx @@ -0,0 +1,102 @@ +import { useLocale } from '@island.is/localization' +import { FormScreen } from '../components/form/FormScreen' +import { involvedParty } from '../lib/messages' +import { InputFields, OJOIFieldBaseProps } from '../lib/types' +import { useInvolvedParties } from '../hooks/useInvolvedParties' +import { OJOISelectController } from '../components/input/OJOISelectController' +import { AlertMessage, Box, Stack } from '@island.is/island-ui/core' +import { useApplication } from '../hooks/useUpdateApplication' +import { useFormContext } from 'react-hook-form' +import set from 'lodash/set' + +export const InvolvedPartyScreen = ({ + application, + setSubmitButtonDisabled, +}: OJOIFieldBaseProps) => { + const { updateApplication } = useApplication({ + applicationId: application.id, + }) + const { formatMessage: f } = useLocale() + const { setValue } = useFormContext() + + const { involvedParties, error, loading } = useInvolvedParties({ + applicationId: application.id, + onError: () => { + setSubmitButtonDisabled && setSubmitButtonDisabled(true) + }, + onComplete: (data) => { + const involvedParties = + data.officialJournalOfIcelandApplicationGetUserInvolvedParties + .involvedParties + + if (involvedParties.length === 0 || involvedParties.length > 1) { + setSubmitButtonDisabled && setSubmitButtonDisabled(true) + } + + if (involvedParties.length === 1) { + const involvedParty = involvedParties[0] + + setValue(InputFields.advert.involvedPartyId, involvedParty.id) + + const currentAnswers = structuredClone(application.answers) + + const updatedAnswers = set( + currentAnswers, + InputFields.advert.involvedPartyId, + involvedParty.id, + ) + + updateApplication(updatedAnswers) + } + }, + }) + + const options = involvedParties?.map((involvedParty) => ({ + label: involvedParty.title, + value: involvedParty.id, + })) + + const defaultValue = options && options.length === 1 ? options[0].value : '' + + const disableSelect = options?.length === 1 || !!error + + return ( + + + {involvedParties?.length === 0 && ( + + )} + {!!error && ( + + )} + + + + setSubmitButtonDisabled && setSubmitButtonDisabled(false) + } + /> + + + ) +} diff --git a/libs/application/templates/official-journal-of-iceland/src/screens/index.ts b/libs/application/templates/official-journal-of-iceland/src/screens/index.ts index 687837f5001f..9c3c7dcc99e1 100644 --- a/libs/application/templates/official-journal-of-iceland/src/screens/index.ts +++ b/libs/application/templates/official-journal-of-iceland/src/screens/index.ts @@ -7,3 +7,4 @@ export * from './PublishingScreen' export * from './SummaryScreen' export * from './SubmittedScreen' export * from './CommentsScreen' +export * from './InvolvedPartyScreen' diff --git a/libs/clients/official-journal-of-iceland/application/src/clientConfig.json b/libs/clients/official-journal-of-iceland/application/src/clientConfig.json index ea30281a3f28..c46142918e35 100644 --- a/libs/clients/official-journal-of-iceland/application/src/clientConfig.json +++ b/libs/clients/official-journal-of-iceland/application/src/clientConfig.json @@ -272,6 +272,31 @@ "responses": { "204": { "description": "" } } } }, + "/api/v1/applications/{id}/involved-parties": { + "get": { + "operationId": "getInvolvedParties", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "default": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationUserInvolvedPartiesResponse" + } + } + } + } + } + } + }, "/api/v1/health": { "get": { "operationId": "HealthController_", @@ -623,6 +648,13 @@ "attachments": { "type": "object", "description": "Attachments" }, "state": { "type": "string", + "enum": [ + "requirements", + "draft", + "draft_retry", + "submitted", + "complete" + ], "example": "draft", "description": "State of the application" }, @@ -952,6 +984,7 @@ }, "title": { "type": "string", + "enum": ["Frumrit", "Fylgiskjöl"], "description": "Title of the attachment type" }, "slug": { @@ -1013,6 +1046,38 @@ }, "required": ["attachments"] }, + "Institution": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique ID for the institution, GUID format.", + "example": "00000000-0000-0000-0000-000000000000", + "nullable": false + }, + "title": { + "type": "string", + "description": "Title of the institution", + "example": "Dómsmálaráðuneytið" + }, + "slug": { + "type": "string", + "description": "Slug of the institution, used in URLs and API requests.", + "example": "domsmalaraduneytid" + } + }, + "required": ["id", "title", "slug"] + }, + "ApplicationUserInvolvedPartiesResponse": { + "type": "object", + "properties": { + "involvedParties": { + "type": "array", + "items": { "$ref": "#/components/schemas/Institution" } + } + }, + "required": ["involvedParties"] + }, "StreamableFile": { "type": "object", "properties": {} }, "GetPdfUrlResponse": { "type": "object", diff --git a/libs/clients/official-journal-of-iceland/application/src/lib/ojoiApplicationClient.service.ts b/libs/clients/official-journal-of-iceland/application/src/lib/ojoiApplicationClient.service.ts index 48f7a95a5385..f9a6132dd3c5 100644 --- a/libs/clients/official-journal-of-iceland/application/src/lib/ojoiApplicationClient.service.ts +++ b/libs/clients/official-journal-of-iceland/application/src/lib/ojoiApplicationClient.service.ts @@ -15,6 +15,7 @@ import { AddApplicationAttachmentRequest, GetApplicationAttachmentsRequest, DeleteApplicationAttachmentRequest, + GetInvolvedPartiesRequest, } from '../../gen/fetch' import { LOGGER_PROVIDER } from '@island.is/logging' import type { Logger } from '@island.is/logging' @@ -178,4 +179,21 @@ export class OfficialJournalOfIcelandApplicationClientService { params, ) } + + async getUserInvolvedParties(params: GetInvolvedPartiesRequest, auth: Auth) { + try { + const data = await this.ojoiApplicationApiWithAuth( + auth, + ).getInvolvedParties(params) + return data + } catch (error) { + this.logger.warn('Failed to get involved parties', { + error, + applicationId: params.id, + category: LOG_CATEGORY, + }) + + throw error + } + } }