Skip to content

Commit

Permalink
feat(web): Team List - Move frontend logic to the backend (#15965)
Browse files Browse the repository at this point in the history
* Order tags

* Change key

* Tag team members

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
RunarVestmann and kodiakhq[bot] authored Sep 12, 2024
1 parent b5778d2 commit 754cc56
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 82 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useMemo, useState } from 'react'
import { useState } from 'react'
import flatten from 'lodash/flatten'
import { useLazyQuery } from '@apollo/client'

import { TeamList, type TeamListProps } from '@island.is/island-ui/contentful'
import { sortAlpha } from '@island.is/shared/utils'
import { GenericList } from '@island.is/web/components'
import {
type GenericTag,
Expand Down Expand Up @@ -67,43 +66,7 @@ export const TeamMemberListWrapper = ({

const totalItems = itemsResponse?.total ?? 0

const items = useMemo(
() =>
(itemsResponse?.items ?? []).map((item) => {
const tagGroups: { groupLabel: string; tagLabels: string[] }[] = []
for (const tag of item.filterTags ?? []) {
if (!tag.genericTagGroup?.title || !tag.title) {
continue
}
const index = tagGroups.findIndex(
(group) => group.groupLabel === tag.genericTagGroup?.title,
)
if (index >= 0) {
tagGroups[index].tagLabels.push(tag.title)
} else {
tagGroups.push({
groupLabel: tag.genericTagGroup.title,
tagLabels: [tag.title],
})
}

// Add a colon to the end of group labels if it doesn't have one
for (const group of tagGroups) {
if (!group.groupLabel.endsWith(':')) {
group.groupLabel += ':'
}
}
}

tagGroups.sort(sortAlpha('groupLabel'))

return {
...(item as TeamListProps['teamMembers'][number]),
tagGroups,
}
}),
[itemsResponse],
)
const items = itemsResponse?.items ?? []

return (
<GenericList
Expand Down Expand Up @@ -132,7 +95,7 @@ export const TeamMemberListWrapper = ({
tagQueryId={tagQueryId}
>
<TeamList
teamMembers={items}
teamMembers={items as TeamListProps['teamMembers']}
variant="accordion"
prefixes={{
email: activeLocale === 'is' ? 'Netfang:' : 'Email:',
Expand Down
12 changes: 3 additions & 9 deletions apps/web/screens/queries/TeamList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,9 @@ export const GET_TEAM_MEMBERS_QUERY = gql`
title
email
phone
filterTags {
id
title
slug
genericTagGroup {
id
title
slug
}
tagGroups {
groupLabel
tagLabels
}
image {
...ImageFields
Expand Down
3 changes: 3 additions & 0 deletions libs/cms/src/lib/generated/contentfulTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4369,6 +4369,9 @@ export interface ITeamListFields {
/** Filter Tags */
filterTags?: IGenericTag[] | undefined

/** Filter groups */
filterGroups?: IGenericTagGroup[] | undefined

/** Variant */
variant?: 'card' | 'accordion' | undefined
}
Expand Down
48 changes: 40 additions & 8 deletions libs/cms/src/lib/models/teamList.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CacheField } from '@island.is/nest/graphql'
import { ITeamList } from '../generated/contentfulTypes'
import { SystemMetadata } from '@island.is/shared/types'
import { TeamMember, mapTeamMember } from './teamMember.model'
import { GenericTag, mapGenericTag } from './genericTag.model'
import { GenericTag } from './genericTag.model'

@ObjectType()
export class TeamList {
Expand All @@ -23,10 +23,42 @@ export class TeamList {
export const mapTeamList = ({
fields,
sys,
}: ITeamList): SystemMetadata<TeamList> => ({
typename: 'TeamList',
id: sys.id,
teamMembers: (fields.teamMembers ?? []).map(mapTeamMember),
variant: fields.variant === 'accordion' ? 'accordion' : 'card',
filterTags: fields.filterTags ? fields.filterTags.map(mapGenericTag) : [],
})
}: ITeamList): SystemMetadata<TeamList> => {
const teamMembers = (fields.teamMembers ?? []).map(mapTeamMember)

const filterTags: GenericTag[] = []

for (const teamMember of teamMembers) {
for (const tag of teamMember.filterTags ?? []) {
const tagBelongsToAFilterGroup = fields.filterGroups?.some(
(group) => group?.sys?.id === tag?.genericTagGroup?.id,
)
if (tag?.genericTagGroup?.id && tagBelongsToAFilterGroup) {
const tagHasAlreadyBeenAdded = filterTags.some((t) => t.id === tag.id)
if (!tagHasAlreadyBeenAdded) {
filterTags.push(tag)
}
}
}

// Reorder the team member tag groups so they are in the same order as the team list filter groups
const tagGroups = []
for (const filterGroup of fields.filterGroups ?? []) {
const group = teamMember.tagGroups?.find(
(g) => g.groupId === filterGroup.sys.id,
)
if (group) {
tagGroups.push(group)
}
}
teamMember.tagGroups = tagGroups
}

return {
typename: 'TeamList',
id: sys.id,
teamMembers,
variant: fields.variant === 'accordion' ? 'accordion' : 'card',
filterTags,
}
}
79 changes: 68 additions & 11 deletions libs/cms/src/lib/models/teamMember.model.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
import { Field, ObjectType } from '@nestjs/graphql'
import { Field, ObjectType, ID } from '@nestjs/graphql'
import { CacheField } from '@island.is/nest/graphql'
import { ITeamMember } from '../generated/contentfulTypes'
import { Image, mapImage } from './image.model'
import { GenericTag, mapGenericTag } from './genericTag.model'
import { SliceUnion, mapDocument } from '../unions/slice.union'

@ObjectType()
export class TeamMemberTagGroup {
@Field()
groupId!: string

@Field()
groupLabel!: string

@Field(() => [String])
tagLabels!: string[]
}

@ObjectType()
export class TeamMember {
@Field(() => ID)
id?: string

@Field()
name!: string

Expand All @@ -30,15 +45,57 @@ export class TeamMember {

@CacheField(() => [SliceUnion], { nullable: true })
intro?: Array<typeof SliceUnion> = []

@CacheField(() => [TeamMemberTagGroup], { nullable: true })
tagGroups?: TeamMemberTagGroup[]

@Field({ nullable: true })
createdAt?: string
}

export const mapTeamMember = ({ fields, sys }: ITeamMember): TeamMember => ({
name: fields.name ?? '',
title: fields.title ?? '',
image: mapImage(fields.mynd),
imageOnSelect: fields.imageOnSelect ? mapImage(fields.imageOnSelect) : null,
filterTags: fields.filterTags ? fields.filterTags.map(mapGenericTag) : [],
intro: fields.intro ? mapDocument(fields.intro, `${sys.id}:intro`) : [],
email: fields.email,
phone: fields.phone,
})
export const mapTeamMember = ({ fields, sys }: ITeamMember): TeamMember => {
const tagGroups: TeamMemberTagGroup[] = []

const filterTags = fields.filterTags
? fields.filterTags.map(mapGenericTag)
: []

for (const tag of filterTags) {
if (!tag.genericTagGroup?.title || !tag.title) {
continue
}
const index = tagGroups.findIndex(
(group) => group.groupLabel === tag.genericTagGroup?.title,
)
if (index >= 0) {
tagGroups[index].tagLabels.push(tag.title)
} else {
tagGroups.push({
groupLabel: tag.genericTagGroup.title,
tagLabels: [tag.title],
groupId: tag.genericTagGroup.id,
})
}

// Add a colon to the end of group labels if it doesn't have one
for (const group of tagGroups) {
if (!group.groupLabel.endsWith(':')) {
group.groupLabel += ':'
}
}
}

return {
id: sys.id,
name: fields.name ?? '',
title: fields.title ?? '',
image: mapImage(fields.mynd),
imageOnSelect: fields.imageOnSelect ? mapImage(fields.imageOnSelect) : null,
filterTags,
intro: fields.intro ? mapDocument(fields.intro, `${sys.id}:intro`) : [],
email: fields.email,
phone: fields.phone,
tagGroups,
createdAt: sys.createdAt,
}
}
28 changes: 16 additions & 12 deletions libs/cms/src/lib/search/importers/teamList.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { logger } from '@island.is/logging'
import { Injectable } from '@nestjs/common'
import type { ITeamList } from '../../generated/contentfulTypes'
import { CmsSyncProvider, processSyncDataInput } from '../cmsSync.service'
import { mapTeamMember } from '../../models/teamMember.model'
import { mapTeamList } from '../../models/teamList.model'

@Injectable()
export class TeamListSyncService implements CmsSyncProvider<ITeamList> {
Expand All @@ -21,30 +21,34 @@ export class TeamListSyncService implements CmsSyncProvider<ITeamList> {
const teamMembers: MappedData[] = []

for (const teamListEntry of entries) {
for (const teamMemberEntry of teamListEntry.fields.teamMembers ?? []) {
const teamList = mapTeamList(teamListEntry)
for (const member of teamList.teamMembers ?? []) {
try {
const content = teamMemberEntry.fields.name
? teamMemberEntry.fields.name
: undefined

const content = member.name ? member.name : undefined
teamMembers.push({
_id: teamMemberEntry.sys.id,
title: teamMemberEntry.fields.name,
_id: member.id,
title: member.name,
content,
contentWordCount: content?.split(/\s+/).length,
type: 'webTeamMember',
response: JSON.stringify({
...mapTeamMember(teamMemberEntry),
...member,
typename: 'webTeamMember',
}),
tags: [{ key: teamListEntry.sys.id, type: 'referencedBy' }],
dateCreated: teamMemberEntry.sys.createdAt,
tags: [
{ key: teamListEntry.sys.id, type: 'referencedBy' },
...(member.filterTags ?? []).map((tag) => ({
key: tag.slug,
type: 'genericTag',
})),
],
dateCreated: member.createdAt ?? '',
dateUpdated: new Date().getTime().toString(),
})
} catch (error) {
logger.warn('Failed to import Team Member', {
error: error.message,
id: teamMemberEntry?.sys?.id,
id: member?.id,
})
}
}
Expand Down
4 changes: 2 additions & 2 deletions libs/island-ui/contentful/src/lib/TeamList/TeamList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ const TeamMemberAccordionList = ({
}: Pick<TeamListProps, 'teamMembers' | 'prefixes'>) => {
return (
<Accordion singleExpand={false}>
{teamMembers.map((member) => {
const id = `${member.name}-${member.title}`
{teamMembers.map((member, index) => {
const id = `${member.name}-${member.title}-${index}`
return (
<AccordionItem
key={id}
Expand Down

0 comments on commit 754cc56

Please sign in to comment.