From 6a80195b39f4e1e20b68cd8b9f802f46c6865520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3n=20Bjarni=20=C3=93lafsson?= Date: Thu, 17 Oct 2024 10:19:42 +0000 Subject: [PATCH 1/3] Updated graphql layer for comments and fixed editor css. --- .../src/lib/mappers.ts | 11 ++ .../src/lib/ojoiApplication.resolver.ts | 4 +- .../src/lib/ojoiApplication.service.ts | 37 +++- .../src/models/getComments.input.ts | 2 +- .../src/models/getComments.response.ts | 55 ++---- .../src/models/postComment.input.ts | 2 +- .../src/components/comments/Comment.tsx | 73 +++----- .../src/components/comments/CommentList.tsx | 6 +- .../components/htmlEditor/HTMLEditor.css.ts | 172 ++++++++--------- .../components/input/OJOIHtmlController.tsx | 1 - .../src/fields/Comments.tsx | 12 +- .../src/graphql/queries.ts | 36 ++-- .../src/hooks/useComments.ts | 13 +- .../src/hooks/useTypes.ts | 24 ++- .../src/lib/utils.ts | 13 +- .../src/screens/AdvertScreen.tsx | 2 +- .../application/src/clientConfig.json | 176 +++++------------- 17 files changed, 277 insertions(+), 362 deletions(-) diff --git a/libs/api/domains/official-journal-of-iceland-application/src/lib/mappers.ts b/libs/api/domains/official-journal-of-iceland-application/src/lib/mappers.ts index e88a77424d14..96ed537978c9 100644 --- a/libs/api/domains/official-journal-of-iceland-application/src/lib/mappers.ts +++ b/libs/api/domains/official-journal-of-iceland-application/src/lib/mappers.ts @@ -42,3 +42,14 @@ export const mapGetAttachmentType = ( return GetApplicationAttachmentsTypeEnum.Fylgiskjol } } + +type EnumType = { [s: string | number]: string } + +export const safeEnumMapper = ( + val: unknown, + enumType: T, +): T[keyof T] | null => { + const found = Object.values(enumType).find((enumVal) => enumVal === val) + + return found ? (found as T[keyof T]) : null +} 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 24806165906d..60c33adf68f3 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 @@ -36,7 +36,7 @@ export class OfficialJournalOfIcelandApplicationResolver { ) {} @Query(() => GetCommentsResponse, { - name: 'officialJournalOfIcelandApplicationGetComments', + name: 'OJOIAGetComments', }) getComments( @Args('input') input: GetCommentsInput, @@ -46,7 +46,7 @@ export class OfficialJournalOfIcelandApplicationResolver { } @Mutation(() => PostCommentResponse, { - name: 'officialJournalOfIcelandApplicationPostComment', + name: 'OJOIAPostComment', }) postComment( @Args('input') input: PostCommentInput, 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 3e445003a633..16ae03302b89 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 @@ -10,6 +10,7 @@ import { mapAttachmentType, mapGetAttachmentType, mapPresignedUrlType, + safeEnumMapper, } from './mappers' import { AddApplicationAttachmentResponse } from '../models/addApplicationAttachment.response' import { GetApplicationAttachmentInput } from '../models/getApplicationAttachment.input' @@ -18,6 +19,10 @@ 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' +import { + CommentDirection, + GetCommentsResponse, +} from '../models/getComments.response' const LOG_CATEGORY = 'official-journal-of-iceland-application' @@ -29,12 +34,38 @@ export class OfficialJournalOfIcelandApplicationService { private readonly ojoiApplicationService: OfficialJournalOfIcelandApplicationClientService, ) {} - async getComments(input: GetCommentsInput, user: User) { - return this.ojoiApplicationService.getComments(input, user) + async getComments( + input: GetCommentsInput, + user: User, + ): Promise { + const incomingComments = await this.ojoiApplicationService.getComments( + input, + user, + ) + + const mapped = incomingComments.comments.map((c) => { + const directonEnum = + safeEnumMapper(c.direction, CommentDirection) ?? + CommentDirection.RECEIVED + + return { + id: c.id, + age: c.age, + direction: directonEnum, + title: c.title, + comment: c.comment, + creator: c.creator, + receiver: c.receiver, + } + }) + + return { + comments: mapped, + } } async postComment(input: PostCommentInput, user: User) { - const success = this.ojoiApplicationService.postComment( + const success = await this.ojoiApplicationService.postComment( { id: input.id, postApplicationComment: { diff --git a/libs/api/domains/official-journal-of-iceland-application/src/models/getComments.input.ts b/libs/api/domains/official-journal-of-iceland-application/src/models/getComments.input.ts index e7280e28e484..813a6809cfa9 100644 --- a/libs/api/domains/official-journal-of-iceland-application/src/models/getComments.input.ts +++ b/libs/api/domains/official-journal-of-iceland-application/src/models/getComments.input.ts @@ -1,6 +1,6 @@ import { Field, ID, InputType } from '@nestjs/graphql' -@InputType('OfficialJournalOfIcelandApplicationGetCommentsInput') +@InputType('OJOIAGetCommentsInput') export class GetCommentsInput { @Field(() => ID) id!: string diff --git a/libs/api/domains/official-journal-of-iceland-application/src/models/getComments.response.ts b/libs/api/domains/official-journal-of-iceland-application/src/models/getComments.response.ts index fac5a5b5a0c0..6dfb8ae78006 100644 --- a/libs/api/domains/official-journal-of-iceland-application/src/models/getComments.response.ts +++ b/libs/api/domains/official-journal-of-iceland-application/src/models/getComments.response.ts @@ -1,56 +1,39 @@ -import { Field, ID, ObjectType } from '@nestjs/graphql' +import { Field, ID, ObjectType, registerEnumType } from '@nestjs/graphql' -@ObjectType('OfficialJournalOfIcelandApplicationEntity') -export class CaseCommentEntity { - @Field(() => ID) - id!: string - - @Field() - title!: string - - @Field() - slug!: string +export enum CommentDirection { + SENT = 'sent', + RECEIVED = 'received', } -@ObjectType('OfficialJournalOfIcelandApplicationCommentTask') -export class CaseCommentTask { - @Field(() => String, { nullable: true }) - from!: string | null - - @Field(() => String, { nullable: true }) - to!: string | null - @Field(() => CaseCommentEntity) - title!: CaseCommentEntity +registerEnumType(CommentDirection, { + name: 'OJOICommentDirection', +}) - @Field(() => String, { nullable: true }) - comment!: string | null -} - -@ObjectType('OfficialJournalOfIcelandApplicationComment') +@ObjectType('OJOIAComment') export class CaseComment { @Field(() => ID) id!: string @Field() - createdAt!: string + age!: string - @Field() - internal!: boolean + @Field(() => CommentDirection) + direction!: CommentDirection - @Field(() => CaseCommentEntity) - type!: CaseCommentEntity + @Field() + title!: string - @Field(() => CaseCommentEntity) - status!: CaseCommentEntity + @Field(() => String, { nullable: true }) + comment!: string | null @Field(() => String, { nullable: true }) - state!: string | null + creator!: string | null - @Field(() => CaseCommentTask) - task!: CaseCommentTask + @Field(() => String, { nullable: true }) + receiver!: string | null } -@ObjectType('OfficialJournalOfIcelandApplicationGetCommentsResponse') +@ObjectType('OJOIAGetCommentsResponse') export class GetCommentsResponse { @Field(() => [CaseComment]) comments!: CaseComment[] diff --git a/libs/api/domains/official-journal-of-iceland-application/src/models/postComment.input.ts b/libs/api/domains/official-journal-of-iceland-application/src/models/postComment.input.ts index a226457cad5a..b8a543e2220b 100644 --- a/libs/api/domains/official-journal-of-iceland-application/src/models/postComment.input.ts +++ b/libs/api/domains/official-journal-of-iceland-application/src/models/postComment.input.ts @@ -1,6 +1,6 @@ import { Field, ID, InputType } from '@nestjs/graphql' -@InputType('OfficialJournalOfIcelandApplicationPostCommentInput') +@InputType('OJOIAPostCommentInput') export class PostCommentInput { @Field(() => ID) id!: string diff --git a/libs/application/templates/official-journal-of-iceland/src/components/comments/Comment.tsx b/libs/application/templates/official-journal-of-iceland/src/components/comments/Comment.tsx index 571f29e2b32c..4907bba13d81 100644 --- a/libs/application/templates/official-journal-of-iceland/src/components/comments/Comment.tsx +++ b/libs/application/templates/official-journal-of-iceland/src/components/comments/Comment.tsx @@ -2,64 +2,45 @@ import { Box, Icon, Text } from '@island.is/island-ui/core' import * as styles from './Comments.css' import { useLocale } from '@island.is/localization' import { comments } from '../../lib/messages/comments' -import { countDaysAgo } from '../../lib/utils' -import { Maybe } from 'graphql/jsutils/Maybe' -export type Props = { - as?: 'div' | 'li' - date?: string - from?: string - task?: string - comment?: Maybe - type?: 'sent' | 'received' -} +import { OjoiCommentDirection, OjoiaComment } from '@island.is/api/schema' +export type Props = OjoiaComment export const Comment = ({ - as = 'li', - date, - from, - task, + id, + age, + title, + direction, + creator, + receiver, comment, - type, -}: Props) => { - const Wrapper = as - +}: OjoiaComment) => { const { formatMessage: f } = useLocale() - const daysAgo = date ? countDaysAgo(new Date(date)) : null - - const many = f(comments.dates.xDaysAgo, { - days: daysAgo, - }) - - const yesterDay = f(comments.dates.yesterday) - const today = f(comments.dates.today) - - const msg = daysAgo === 0 ? today : daysAgo === 1 ? yesterDay : many - return ( - +
  • - {type && ( - - - - )} + + + - {from ? from : f(comments.unknownUser.name)}{' '} - {task && `${task}`} + {creator ? creator : f(comments.unknownUser.name)}{' '} + {title && `${title}`} + {receiver && ` ${receiver}`} {comment} - - {daysAgo !== null && {msg}} - - + {age} +
  • ) } diff --git a/libs/application/templates/official-journal-of-iceland/src/components/comments/CommentList.tsx b/libs/application/templates/official-journal-of-iceland/src/components/comments/CommentList.tsx index 7da90fa08760..29ab554f1770 100644 --- a/libs/application/templates/official-journal-of-iceland/src/components/comments/CommentList.tsx +++ b/libs/application/templates/official-journal-of-iceland/src/components/comments/CommentList.tsx @@ -1,11 +1,11 @@ import { SkeletonLoader } from '@island.is/island-ui/core' -import type { Props as CommentProps } from './Comment' import { Comment } from './Comment' import * as styles from './Comments.css' import { OJOI_INPUT_HEIGHT } from '../../lib/constants' +import { OjoiaComment } from '@island.is/api/schema' type Props = { - comments?: CommentProps[] + comments?: Array loading?: boolean } @@ -24,7 +24,7 @@ export const CommentsList = ({ comments, loading }: Props) => { return (
      {comments?.map((comment, index) => ( - + ))}
    ) diff --git a/libs/application/templates/official-journal-of-iceland/src/components/htmlEditor/HTMLEditor.css.ts b/libs/application/templates/official-journal-of-iceland/src/components/htmlEditor/HTMLEditor.css.ts index e2b56a691069..948cc49e19b7 100644 --- a/libs/application/templates/official-journal-of-iceland/src/components/htmlEditor/HTMLEditor.css.ts +++ b/libs/application/templates/official-journal-of-iceland/src/components/htmlEditor/HTMLEditor.css.ts @@ -526,92 +526,92 @@ globalStyle(`${classes.warnings__item_high}::marker`, { pointerEvents: 'none', // hax to prevent link clicks :/ }) - global('.signatures', { - display: 'grid', - gap: '1ch', - gridTemplateColumns: '1fr 1fr', - }) - - global('.signature__group + .signature__group', { - marginTop: '3ch', - }) - - global('.signatures.single', { - gridTemplateColumns: '1fr', - }) - - global('.signatures.double', { - gridTemplateColumns: '1fr 1fr', - }) - - global('.signatures.triple', { - gridTemplateColumns: '1fr 1fr 1fr', - }) - - global('.signatures.chairman', { - marginBottom: '2ch', - }) - - global('.signature', { - marginTop: '0', - fontSize: 16, - fontWeight: typography.semiBold, - textAlign: 'center', - }) - - global('.signature__title', { - marginTop: '0', - marginBottom: '1ch', - fontSize: 14, - fontStyle: 'italic', - fontWeight: typography.regular, - textAlign: 'center', - }) - - global('.signature__above', { - marginTop: 0, - marginBottom: 0, - fontSize: 14, - fontStyle: 'normal', - fontWeight: typography.regular, - textAlign: 'center', - }) - - global('.signature__nameWrapper', { - lineHeight: 1.2, - textAlign: 'center', - fontSize: 14, - }) - - global('.signature__name', { - fontWeight: typography.semiBold, - marginBottom: '0', - }) - - global('.signature__textAfter', { - fontSize: 14, - fontWeight: typography.regular, - }) - - global('.signature__textBelow', { - fontSize: 14, - textAlign: 'center', - fontWeight: typography.regular, - }) - - global('.signature__footer', { - marginTop: '2ch', - fontSize: 14, - textAlign: 'center', - fontWeight: typography.semiBold, - }) - - global('.signature__additional', { - marginTop: '2ch', - fontStyle: 'italic', - fontSize: 14, - textAlign: 'right', - }) + // global('.signatures', { + // display: 'grid', + // gap: '1ch', + // gridTemplateColumns: '1fr 1fr', + // }) + + // global('.signature__group + .signature__group', { + // marginTop: '3ch', + // }) + + // global('.signatures.single', { + // gridTemplateColumns: '1fr', + // }) + + // global('.signatures.double', { + // gridTemplateColumns: '1fr 1fr', + // }) + + // global('.signatures.triple', { + // gridTemplateColumns: '1fr 1fr 1fr', + // }) + + // global('.signatures.chairman', { + // marginBottom: '2ch', + // }) + + // global('.signature', { + // marginTop: '0', + // // fontSize: 16, + // fontWeight: typography.semiBold, + // textAlign: 'center', + // }) + + // global('.signature__title', { + // marginTop: '0', + // marginBottom: '1ch', + // // fontSize: 14, + // fontStyle: 'italic', + // fontWeight: typography.regular, + // textAlign: 'center', + // }) + + // global('.signature__above', { + // marginTop: 0, + // marginBottom: 0, + // // fontSize: 14, + // fontStyle: 'normal', + // fontWeight: typography.regular, + // textAlign: 'center', + // }) + + // global('.signature__nameWrapper', { + // lineHeight: 1.2, + // textAlign: 'center', + // fontSize: 14, + // }) + + // global('.signature__name', { + // fontWeight: typography.semiBold, + // marginBottom: '0', + // }) + + // global('.signature__textAfter', { + // fontSize: 14, + // fontWeight: typography.regular, + // }) + + // global('.signature__textBelow', { + // fontSize: 14, + // textAlign: 'center', + // fontWeight: typography.regular, + // }) + + // global('.signature__footer', { + // marginTop: '2ch', + // fontSize: 14, + // textAlign: 'center', + // fontWeight: typography.semiBold, + // }) + + // global('.signature__additional', { + // marginTop: '2ch', + // fontStyle: 'italic', + // fontSize: 14, + // textAlign: 'right', + // }) global('.document-content', { marginBottom: '2ch', diff --git a/libs/application/templates/official-journal-of-iceland/src/components/input/OJOIHtmlController.tsx b/libs/application/templates/official-journal-of-iceland/src/components/input/OJOIHtmlController.tsx index d3426936f725..9eb509949f6c 100644 --- a/libs/application/templates/official-journal-of-iceland/src/components/input/OJOIHtmlController.tsx +++ b/libs/application/templates/official-journal-of-iceland/src/components/input/OJOIHtmlController.tsx @@ -54,7 +54,6 @@ export const OJOIHtmlController = ({ > { paddingBottom={5} background="blue100" > - { - return { - task: comment.task.title.title, - comment: comment.task.comment, - from: comment.task.from ?? undefined, - date: comment.createdAt, - type: 'received', // TODO: Implement sent comments - } - })} - /> + )} { }, }) + console.log('data', data) + const addComment = (variables: AddCommentVariables, cb?: () => void) => { addCommentMutation({ variables: { @@ -60,14 +62,13 @@ export const useComments = ({ applicationId }: Props) => { } return { - comments: data?.officialJournalOfIcelandApplicationGetComments.comments, + comments: data?.OJOIAGetComments.comments, loading, error, refetchComments: refetch, addComment, addCommentLoading, addCommentError, - addCommentSuccess: - addCommentSuccess?.officialJournalOfIcelandApplicationPostComment.success, + addCommentSuccess: addCommentSuccess?.OJOIAPostComment.success, } } diff --git a/libs/application/templates/official-journal-of-iceland/src/hooks/useTypes.ts b/libs/application/templates/official-journal-of-iceland/src/hooks/useTypes.ts index 61d05bb9a6c7..26e1ec4cf53f 100644 --- a/libs/application/templates/official-journal-of-iceland/src/hooks/useTypes.ts +++ b/libs/application/templates/official-journal-of-iceland/src/hooks/useTypes.ts @@ -5,6 +5,8 @@ import { TYPES_QUERY } from '../graphql/queries' type UseTypesParams = { initalDepartmentId?: string + pageSize?: number + page?: number } type TypesResponse = { @@ -13,7 +15,7 @@ type TypesResponse = { type TypesVariables = { params: { - department: string + department?: string page?: number pageSize?: number } @@ -22,16 +24,26 @@ type TypesVariables = { export const useTypes = ({ initalDepartmentId: departmentId, }: UseTypesParams) => { + const params: TypesVariables['params'] = {} + + if (departmentId) { + params.department = departmentId + } + + if (!params.page) { + params.page = 1 + } + + if (!params.pageSize) { + params.pageSize = 1000 + } + const { data, loading, error, refetch, networkStatus } = useQuery< TypesResponse, TypesVariables >(TYPES_QUERY, { variables: { - params: { - department: departmentId ?? '', - page: 1, - pageSize: 1000, - }, + params: params, }, notifyOnNetworkStatusChange: true, }) diff --git a/libs/application/templates/official-journal-of-iceland/src/lib/utils.ts b/libs/application/templates/official-journal-of-iceland/src/lib/utils.ts index 01104ff2486c..65084060246f 100644 --- a/libs/application/templates/official-journal-of-iceland/src/lib/utils.ts +++ b/libs/application/templates/official-journal-of-iceland/src/lib/utils.ts @@ -176,7 +176,7 @@ const getMembersMarkup = (member: z.infer) => { } const aboveMarkup = member.above - ? `

    ${member.above}

    ` + ? `

    ${member.above}

    ` : '' const afterMarkup = member.after ? ` ${member.after}` : '' const belowMarkup = member.below @@ -184,7 +184,7 @@ const getMembersMarkup = (member: z.infer) => { : '' return ` -
    +
    ${aboveMarkup}

    ${member.name}${afterMarkup}

    ${belowMarkup} @@ -199,15 +199,16 @@ const signatureTemplate = ( ) => { const markup = signatures ?.map((signature) => { - const membersCount = Math.min(signature.members?.length ?? 1, 3) + const membersCount = signature?.members?.length || 0 + const styleObject = { display: membersCount > 1 ? 'grid' : 'block', gridTemplateColumns: membersCount === 1 ? '1fr' - : membersCount === 2 || membersCount === 4 - ? '1fr 1fr' - : '1fr 1fr 1fr', + : membersCount === 3 + ? '1fr 1fr 1fr' + : '1fr 1fr', } const date = signature.date diff --git a/libs/application/templates/official-journal-of-iceland/src/screens/AdvertScreen.tsx b/libs/application/templates/official-journal-of-iceland/src/screens/AdvertScreen.tsx index faf9108c8961..faee6dee3f07 100644 --- a/libs/application/templates/official-journal-of-iceland/src/screens/AdvertScreen.tsx +++ b/libs/application/templates/official-journal-of-iceland/src/screens/AdvertScreen.tsx @@ -7,7 +7,7 @@ import { Button } from '@island.is/island-ui/core' import { Advert } from '../fields/Advert' import { Signatures } from '../fields/Signatures' import { AdvertModal } from '../fields/AdvertModal' - +import { Comments } from '../fields/Comments' export const AdvertScreen = (props: OJOIFieldBaseProps) => { const { formatMessage: f } = useLocale() const [modalVisible, setModalVisability] = useState(false) 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 c46142918e35..238cd916d020 100644 --- a/libs/clients/official-journal-of-iceland/application/src/clientConfig.json +++ b/libs/clients/official-journal-of-iceland/application/src/clientConfig.json @@ -433,6 +433,11 @@ "ApplicationAdvert": { "type": "object", "properties": { + "involvedPartyId": { + "type": "string", + "example": "a12c3d4e-5f67-8h90-1i23-j45k6l7m8n9o0", + "description": "Id of the involved party" + }, "departmentId": { "type": "string", "example": "a12c3d4e-5f67-8h90-1i23-j45k6l7m8n9o0", @@ -473,6 +478,7 @@ } }, "required": [ + "involvedPartyId", "departmentId", "typeId", "title", @@ -734,39 +740,35 @@ "required": ["application"] }, "CaseCommentType": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "The title of the case comment type" - }, - "title": { - "type": "string", - "enum": [ - "submit", - "assign", - "assign-self", - "update", - "comment", - "message" - ], - "description": "The title of the case comment type" - }, - "slug": { - "type": "string", - "description": "The slug of the case comment type" - } - }, - "required": ["id", "title", "slug"] + "type": "string", + "description": "Title of the comment", + "enum": [ + "Innsent af:", + "færir mál á", + "merkir sér málið.", + "færir mál í stöðuna:", + "gerir athugasemd.", + "skráir skilaboð" + ] }, - "CaseStatus": { + "CaseCommentDirection": { + "type": "string", + "description": "Was the comment sent or received.", + "enum": ["sent", "received"] + }, + "CaseComment": { "type": "object", "properties": { "id": { "type": "string", - "example": "d290f1ee-6c54-4b01-90e6-d701748f0851" + "example": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "description": "Id of the case comment." }, "title": { + "example": "f. 2 dögum", + "$ref": "#/components/schemas/CaseCommentType" + }, + "caseStatus": { "type": "string", "enum": [ "Innsent", @@ -777,120 +779,38 @@ "Tekið úr birtingu", "Birtingu hafnað" ], - "example": "Innsent", - "description": "Status of the case" + "description": "Case status of when the comment was created." }, - "slug": { + "age": { "type": "string", - "example": "innsent", - "description": "Slug of the case staus" - } - }, - "required": ["id", "title", "slug"] - }, - "CaseCommentTitle": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "The title of the case comment type" + "example": "f. 2 dögum", + "description": "String representation of the age of the case comment." }, - "title": { + "ageIso": { "type": "string", - "enum": [ - "Innsent af:", - "færir mál á", - "merkir sér málið.", - "færir mál í stöðuna:", - "gerir athugasemd.", - "skráir skilaboð" - ], - "description": "The title of the case comment type" + "description": "ISO date format representation of the age of the case comment." }, - "slug": { + "direction": { "$ref": "#/components/schemas/CaseCommentDirection" }, + "creator": { "type": "string", - "description": "The slug of the case comment type" - } - }, - "required": ["id", "title", "slug"] - }, - "CaseCommentTask": { - "type": "object", - "properties": { - "from": { - "type": "string", - "description": "From who or what initied the task, used by client to show who inited the task.", - "example": "Ármann", - "nullable": true + "description": "Who created the comment " }, - "to": { + "receiver": { "type": "string", - "description": "To whom or what the task is assigned to.", - "example": "Pálina J", - "nullable": true - }, - "title": { - "description": "Title for the task action", - "allOf": [{ "$ref": "#/components/schemas/CaseCommentTitle" }] + "description": "Who received the comment" }, - "comment": { - "type": "string", - "description": "The comment itself", - "example": "Pálína, getur þú tekið við og staðfest að upplýsingarnar séu réttar?", - "nullable": true - } - }, - "required": ["from", "to", "title", "comment"] - }, - "CaseComment": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "d290f1ee-6c54-4b01-90e6-d701748f0851", - "description": "Id of the case comment." - }, - "createdAt": { - "type": "string", - "description": "Date and time of the comment, ISO 8601 format, UTC time format.", - "example": "2024-01-01T09:00:00Z" - }, - "internal": { - "type": "boolean", - "description": "Is the comment internal or external.", - "example": false - }, - "type": { - "description": "Type of the case task.", - "allOf": [{ "$ref": "#/components/schemas/CaseCommentType" }] - }, - "status": { - "description": "Status of case when comment was added.", - "allOf": [{ "$ref": "#/components/schemas/CaseStatus" }] - }, - "state": { - "type": "string", - "description": "JSON state of the application" - }, - "task": { - "example": { - "from": "Ármann", - "to": null, - "title": "gerir athugasemd", - "comment": "Pálína, getur\n þú tekið við og staðfest að upplýsingarnar séu réttar?" - }, - "description": "The task itself", - "allOf": [{ "$ref": "#/components/schemas/CaseCommentTask" }] - } + "comment": { "type": "string", "description": "The comment itself" } }, "required": [ "id", - "createdAt", - "internal", - "type", - "status", - "state", - "task" + "title", + "caseStatus", + "age", + "ageIso", + "direction", + "creator", + "receiver", + "comment" ] }, "GetCaseCommentsResponse": { From 8e24e3a29fa804b155f774dbca028339c563336f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3n=20Bjarni=20=C3=93lafsson?= Date: Fri, 18 Oct 2024 14:48:36 +0000 Subject: [PATCH 2/3] Search now working properly. --- .../OfficialJournalOfIceland/OJOIUtils.ts | 4 +- .../OfficialJournalOfIceland/OJOIHome.tsx | 2 - .../OfficialJournalOfIceland/OJOISearch.tsx | 468 ++++++++++++------ .../OfficialJournalOfIceland/hooks/index.ts | 1 + .../hooks/useAdverts.ts | 55 ++ .../lib/advert-params.mapper.ts | 43 ++ 6 files changed, 431 insertions(+), 142 deletions(-) create mode 100644 apps/web/screens/OfficialJournalOfIceland/hooks/index.ts create mode 100644 apps/web/screens/OfficialJournalOfIceland/hooks/useAdverts.ts create mode 100644 apps/web/screens/OfficialJournalOfIceland/lib/advert-params.mapper.ts diff --git a/apps/web/components/OfficialJournalOfIceland/OJOIUtils.ts b/apps/web/components/OfficialJournalOfIceland/OJOIUtils.ts index 0c60d31b0225..e731a8059ea3 100644 --- a/apps/web/components/OfficialJournalOfIceland/OJOIUtils.ts +++ b/apps/web/components/OfficialJournalOfIceland/OJOIUtils.ts @@ -17,7 +17,9 @@ export const splitArrayIntoGroups = (array: Array, groupSize: number) => { ) } -export const removeEmptyFromObject = (obj: Record) => { +export const removeEmptyFromObject = ( + obj: Record, +) => { return Object.entries(obj) .filter(([_, v]) => !!v) .reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {}) diff --git a/apps/web/screens/OfficialJournalOfIceland/OJOIHome.tsx b/apps/web/screens/OfficialJournalOfIceland/OJOIHome.tsx index 83418431d798..6af57b49482b 100644 --- a/apps/web/screens/OfficialJournalOfIceland/OJOIHome.tsx +++ b/apps/web/screens/OfficialJournalOfIceland/OJOIHome.tsx @@ -32,10 +32,8 @@ import { withMainLayout } from '@island.is/web/layouts/main' import { CustomNextError } from '@island.is/web/units/errors' import { - OJOIAdvertCard, OJOIAdvertCards, OJOIHomeIntro, - OJOISearchListView, OJOIWrapper, } from '../../components/OfficialJournalOfIceland' import { diff --git a/apps/web/screens/OfficialJournalOfIceland/OJOISearch.tsx b/apps/web/screens/OfficialJournalOfIceland/OJOISearch.tsx index c253999cd919..4a03a4afde86 100644 --- a/apps/web/screens/OfficialJournalOfIceland/OJOISearch.tsx +++ b/apps/web/screens/OfficialJournalOfIceland/OJOISearch.tsx @@ -1,16 +1,17 @@ -import { useEffect, useMemo, useState } from 'react' +import { useCallback, useMemo, useState } from 'react' import { useIntl } from 'react-intl' import debounce from 'lodash/debounce' import { useRouter } from 'next/router' -import { useLazyQuery } from '@apollo/client' import { + AlertMessage, Box, Button, DatePicker, Divider, Input, Select, + SkeletonLoader, Stack, Text, } from '@island.is/island-ui/core' @@ -22,7 +23,6 @@ import { OfficialJournalOfIcelandAdvert, OfficialJournalOfIcelandAdvertCategory, OfficialJournalOfIcelandAdvertEntity, - OfficialJournalOfIcelandAdvertsResponse, OfficialJournalOfIcelandAdvertType, Query, QueryGetOrganizationArgs, @@ -57,104 +57,178 @@ import { INSTITUTIONS_QUERY, TYPES_QUERY, } from '../queries/OfficialJournalOfIceland' +import { useAdverts } from './hooks' import { m } from './messages' -const initialState = { - sida: '', - q: '', - deild: '', // department - tegund: '', // type - timabil: '', // dateFrom - dateTo - malaflokkur: '', // category - stofnun: '', // involvedParty - dagsFra: '', - dagsTil: '', +type OJOISearchParams = { + q: string + deild: string + tegund: string + timabil: string + malaflokkur: string + stofnun: string + dagsFra?: string // DATE STRING + dagsTil?: string // DATE STRING + sida?: number + staerd?: number } const OJOISearchPage: CustomScreen = ({ initialAdverts, categories, departments, + defaultSearchParams, types, institutions, organization, locale, }) => { const { formatMessage } = useIntl() - const router = useRouter() const { linkResolver } = useLinkResolver() + const router = useRouter() - const [adverts, setAdverts] = useState(initialAdverts) - - const [searchState, setSearchState] = useState(initialState) const [listView, setListView] = useState(false) const baseUrl = linkResolver('ojoihome', [], locale).href const searchUrl = linkResolver('ojoisearch', [], locale).href - const [getAdverts] = useLazyQuery< - { - officialJournalOfIcelandAdverts: OfficialJournalOfIcelandAdvertsResponse + const getTimestamp = () => new Date().getTime() + const [resetTimestamp, setResetTimestamp] = useState(0) + + const [localSearchValue, setLocalSearchValue] = useState( + defaultSearchParams.q, + ) + + const { adverts, loading, error, refetch } = useAdverts({ + vars: { + department: [defaultSearchParams.deild], + category: [defaultSearchParams.malaflokkur], + involvedParty: [defaultSearchParams.stofnun], + type: [defaultSearchParams.tegund], + dateFrom: defaultSearchParams.dagsFra + ? new Date(defaultSearchParams.dagsFra) + : undefined, + dateTo: defaultSearchParams.dagsTil + ? new Date(defaultSearchParams.dagsTil) + : undefined, + search: defaultSearchParams.q, + page: defaultSearchParams.sida, + pageSize: defaultSearchParams.staerd, }, - QueryOfficialJournalOfIcelandAdvertsArgs - >(ADVERTS_QUERY, { fetchPolicy: 'no-cache' }) + fallbackData: initialAdverts, + }) + + const [searchState, setSearchState] = useState({ + q: defaultSearchParams.q, + deild: defaultSearchParams.deild, + tegund: defaultSearchParams.tegund, + timabil: defaultSearchParams.timabil, + malaflokkur: defaultSearchParams.malaflokkur, + stofnun: defaultSearchParams.stofnun, + dagsFra: defaultSearchParams.dagsFra, + dagsTil: defaultSearchParams.dagsTil, + sida: defaultSearchParams.sida, + staerd: defaultSearchParams.staerd, + }) + + const updateSearchStateHandler = useCallback( + ( + key: keyof typeof searchState, + value: string | number | Date | undefined, + ) => { + const parsed = + typeof value === 'string' + ? value.trim() + : typeof value === 'number' + ? value + : value instanceof Date + ? value + : undefined + + setSearchState((prev) => ({ + ...prev, + [key]: parsed, + })) + + const searchValues = { + ...searchState, + [key]: parsed, + } - useEffect(() => { - const searchParams = new URLSearchParams(document.location.search) - setSearchState({ - sida: searchParams.get('sida') ?? '', - q: searchParams.get('q') ?? '', - deild: searchParams.get('deild') ?? '', - tegund: searchParams.get('tegund') ?? '', - timabil: searchParams.get('timabil') ?? '', - malaflokkur: searchParams.get('malaflokkur') ?? '', - stofnun: searchParams.get('stofnun') ?? '', - dagsFra: searchParams.get('dagsFra') ?? '', - dagsTil: searchParams.get('dagsTil') ?? '', - }) - }, []) - - const fetchAdverts = useMemo(() => { - return debounce((state: typeof initialState) => { - getAdverts({ - variables: { - input: { - search: state.q, - page: state.sida ? parseInt(state.sida) : undefined, - department: state.deild ? [state.deild] : undefined, - type: state.tegund ? [state.tegund] : undefined, - category: state.malaflokkur ? [state.malaflokkur] : undefined, - involvedParty: state.stofnun ? [state.stofnun] : undefined, - dateFrom: state.dagsFra ? new Date(state.dagsFra) : undefined, - dateTo: state.dagsTil ? new Date(state.dagsTil) : undefined, - }, + router.replace( + { + pathname: searchUrl, + query: removeEmptyFromObject({ + ...searchValues, + [key]: + parsed instanceof Date + ? parsed.toISOString().split('T')[0] + : parsed, + }), + }, + undefined, + { shallow: true }, + ) + + refetch({ + input: { + department: [searchValues.deild], + category: [searchValues.malaflokkur], + involvedParty: [searchValues.stofnun], + type: [searchValues.tegund], + dateFrom: searchValues.dagsFra + ? new Date(searchValues.dagsFra) + : undefined, + dateTo: searchValues.dagsTil + ? new Date(searchValues.dagsTil) + : undefined, + search: searchValues.q, + page: searchValues.sida, + pageSize: searchValues.staerd, }, }) - .then((res) => { - if (res.data) { - setAdverts(res.data.officialJournalOfIcelandAdverts.adverts) - } else if (res.error) { - setAdverts([]) - console.error('Error fetching Adverts', res.error) - } - }) - .catch((err) => { - setAdverts([]) - console.error('Error fetching Adverts', { err }) - }) - }, debounceTime.search) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - useEffect(() => { - const isEmpty = !Object.entries(searchState).filter(([_, v]) => !!v).length - if (isEmpty) { - setAdverts(initialAdverts) - } else { - fetchAdverts(searchState) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [searchState]) + }, + + [refetch, router, searchState, searchUrl], + ) + + const resetFilter = () => { + router.replace(searchUrl, {}, { shallow: true }) + setLocalSearchValue('') + setSearchState({ + q: '', + deild: '', + tegund: '', + timabil: '', + malaflokkur: '', + stofnun: '', + dagsFra: undefined, + dagsTil: undefined, + sida: 1, + staerd: 20, + }) + + refetch({ + input: { + department: [], + category: [], + involvedParty: [], + type: [], + dateFrom: undefined, + dateTo: undefined, + search: '', + page: undefined, + pageSize: undefined, + }, + }) + + setResetTimestamp(getTimestamp()) + } + + const categoriesOptions = mapEntityToOptions(categories) + const departmentsOptions = mapEntityToOptions(departments) + const typesOptions = mapEntityToOptions(types) + const institutionsOptions = mapEntityToOptions(institutions) const breadcrumbItems = [ { @@ -170,38 +244,25 @@ const OJOISearchPage: CustomScreen = ({ }, ] - const updateSearchParams = useMemo(() => { - return debounce((state: Record) => { - router.replace( - searchUrl, - { - query: removeEmptyFromObject(state), - }, - { shallow: true }, - ) - }, debounceTime.search) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - const updateSearchState = (key: keyof typeof initialState, value: string) => { - const newState = { - ...searchState, - [key]: value, - } - setSearchState(newState) - updateSearchParams(newState) - } + const debouncedSearch = useMemo( + () => debounce(updateSearchStateHandler, debounceTime.search), + [updateSearchStateHandler], + ) - const resetFilter = () => { - setSearchState(initialState) - updateSearchParams(initialState) - setAdverts(initialAdverts) - } + const debouncedSearchHandler = useCallback( + (search: string) => { + debouncedSearch.cancel() + debouncedSearch('q', search) + }, + [debouncedSearch], + ) - const categoriesOptions = mapEntityToOptions(categories) - const departmentsOptions = mapEntityToOptions(departments) - const typesOptions = mapEntityToOptions(types) - const institutionsOptions = mapEntityToOptions(institutions) + const defaultDepartment = departmentsOptions.find( + (d) => d.value === defaultSearchParams.deild, + ) + + console.log(defaultSearchParams) + console.log('defaultdepartment', defaultDepartment) return ( = ({ Leit updateSearchState('q', e.target.value)} + defaultValue={searchState.q} + value={localSearchValue} + onChange={(e) => { + setLocalSearchValue(e.target.value) + debouncedSearchHandler(e.target.value) + }} /> @@ -245,6 +311,7 @@ const OJOISearchPage: CustomScreen = ({ = ({ ...typesOptions, ]} isClearable - value={findValueOption(typesOptions, searchState.tegund)} - onChange={(v) => updateSearchState('tegund', v?.value ?? '')} + defaultValue={findValueOption(typesOptions, searchState.tegund)} + onChange={(v) => + updateSearchStateHandler('tegund', v?.value ?? '') + } /> = ({ ]} isClearable isSearchable - value={findValueOption(institutionsOptions, searchState.stofnun)} - onChange={(v) => updateSearchState('stofnun', v?.value ?? '')} + defaultValue={findValueOption( + institutionsOptions, + searchState.stofnun, + )} + onChange={(v) => + updateSearchStateHandler('stofnun', v?.value ?? '') + } /> } breadcrumbItems={breadcrumbItems} > - {adverts?.length ? ( + {!!error && ( + + + + )} + {loading ? ( + + ) : adverts?.length ? (