Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web): grant slice for articles #17262

Draft
wants to merge 29 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3453691
feat: init
thorkellmani Nov 20, 2024
1769fa8
feat: slice works
thorkellmani Nov 20, 2024
a549c07
fix: link color
thorkellmani Nov 20, 2024
9e1759b
fix: removing logging
thorkellmani Nov 20, 2024
cfb5e77
fix: another log
thorkellmani Nov 20, 2024
49ffb96
fix: merge
thorkellmani Dec 16, 2024
087b2ee
feat: merge in info card
thorkellmani Dec 16, 2024
96c688f
feat: works a bit
thorkellmani Dec 16, 2024
2635d1e
Merge branch 'main' into feat/grant-slice
thorkellmani Dec 17, 2024
fa1197b
fix: build bug
thorkellmani Dec 17, 2024
47fb2de
Merge branch 'main' into feat/grant-slice
thorkellmani Dec 17, 2024
bf5d54f
Merge branch 'main' into feat/grant-slice
thorkellmani Dec 17, 2024
ed7e357
feat: wip
thorkellmani Dec 17, 2024
ca8eed3
feat: works much better
thorkellmani Dec 17, 2024
e329c27
feat: merge info card
thorkellmani Dec 17, 2024
1986325
chore: remove unused files
thorkellmani Dec 17, 2024
9070ba5
chore: remove not my contentful updates
thorkellmani Dec 17, 2024
50d74fe
chore: fix up tags
thorkellmani Dec 17, 2024
8d33ff6
feat: different ui for 1 grant
thorkellmani Dec 18, 2024
78c8ed8
fix: use fund in query
thorkellmani Dec 18, 2024
b6b8ce4
Merge branch 'main' into feat/grant-slice
thorkellmani Dec 18, 2024
71a8d65
fix: review comments
thorkellmani Dec 18, 2024
4f93471
Merge remote-tracking branch 'refs/remotes/origin/feat/grant-slice' i…
thorkellmani Dec 18, 2024
7d6dc62
Merge branch 'main' into feat/grant-slice
thorkellmani Dec 18, 2024
8cec6a0
Merge branch 'main' into feat/grant-slice
thorkellmani Dec 18, 2024
c5a8b46
fix: add import
thorkellmani Dec 18, 2024
6c5db77
chore: remove import
thorkellmani Dec 18, 2024
dfadc61
Merge branch 'main' into feat/grant-slice
thorkellmani Dec 18, 2024
56eed5a
fix: import different
thorkellmani Dec 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const DEFAULT_EDITABLE_ENTRY_TYPE_IDS = [
'genericTag',
'genericTagGroup',
'graphCard',
'grantCardsList',
'latestNewsSlice',
'linkGroup',
'menuLink',
Expand Down
192 changes: 192 additions & 0 deletions apps/web/components/GrantCardsList/GrantCardsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import format from 'date-fns/format'
import localeEN from 'date-fns/locale/en-GB'
import localeIS from 'date-fns/locale/is'
import { useRouter } from 'next/router'

import { ActionCard, Box, InfoCardGrid } from '@island.is/island-ui/core'
import { Locale } from '@island.is/shared/types'
import { isDefined } from '@island.is/shared/utils'
import {
Grant,
GrantCardsList as GrantCardsListSchema,
GrantStatus,
} from '@island.is/web/graphql/schema'
import { useLinkResolver } from '@island.is/web/hooks'
import { useI18n } from '@island.is/web/i18n'

import { TranslationKeys } from './types'

interface SliceProps {
slice: GrantCardsListSchema
}

const formatDate = (
date: Date,
locale: Locale,
stringFormat = 'dd. MMMM yyyy',
): string | undefined => {
try {
return format(date, stringFormat, {
locale: locale === 'is' ? localeIS : localeEN,
})
} catch (e) {
console.warn('Error formatting date')
return
}
}

const containsTimePart = (date: string) => date.includes('T')

const GrantCardsList = ({ slice }: SliceProps) => {
const { activeLocale } = useI18n()
const { linkResolver } = useLinkResolver()
const router = useRouter()

const namespace = slice.namespace

const getTranslationString = (
key: keyof TranslationKeys,
argToInterpolate?: string,
) =>
argToInterpolate
? namespace[key].replace('{arg}', argToInterpolate)
: namespace[key]

const parseStatus = (grant: Grant): string | undefined => {
switch (grant.status) {
case GrantStatus.Closed: {
const date = grant.dateTo
? formatDate(new Date(grant.dateTo), activeLocale)
: undefined
return date
? getTranslationString(
containsTimePart(date)
? 'applicationWasOpenToAndWith'
: 'applicationWasOpenTo',
date,
)
: getTranslationString('applicationClosed')
}
case GrantStatus.ClosedOpeningSoon: {
const date = grant.dateFrom
? formatDate(new Date(grant.dateFrom), activeLocale)
: undefined
return date
? getTranslationString('applicationOpensAt', date)
: getTranslationString('applicationClosed')
}
case GrantStatus.ClosedOpeningSoonWithEstimation: {
const date = grant.dateFrom
? formatDate(new Date(grant.dateFrom), activeLocale, 'MMMM yyyy')
: undefined
return date
? getTranslationString('applicationEstimatedOpensAt', date)
: getTranslationString('applicationClosed')
}
case GrantStatus.AlwaysOpen: {
return getTranslationString('applicationAlwaysOpen')
}
case GrantStatus.Open: {
const date = grant.dateTo
? formatDate(new Date(grant.dateTo), activeLocale, 'dd. MMMM.')
: undefined
return date
? getTranslationString(
containsTimePart(date)
? 'applicationOpensToWithDay'
: 'applicationOpensTo',
date,
)
: getTranslationString('applicationOpen')
}
case GrantStatus.ClosedWithNote:
case GrantStatus.OpenWithNote: {
return getTranslationString('applicationSeeDescription')
}
default:
return
}
}
thorkellmani marked this conversation as resolved.
Show resolved Hide resolved

if (slice.resolvedGrantsList?.items.length === 1) {
const grant = slice.resolvedGrantsList.items[0]
return (
<ActionCard
heading={grant.name}
backgroundColor="blue"
cta={{
disabled: !grant.applicationUrl?.slug,
label: grant.applicationButtonLabel ?? getTranslationString('apply'),
onClick: () => router.push(grant.applicationUrl?.slug ?? ''),
icon: 'open',
iconType: 'outline',
}}
/>
)
}

const cards = slice.resolvedGrantsList?.items
?.map((grant) => {
if (grant.id) {
return {
id: grant.id,
eyebrow: grant.fund?.title ?? grant.name ?? '',
subEyebrow: grant.fund?.parentOrganization?.title,
title: grant.name ?? '',
description: grant.description ?? '',
logo:
grant.fund?.featuredImage?.url ??
grant.fund?.parentOrganization?.logo?.url ??
'',
logoAlt:
grant.fund?.featuredImage?.title ??
grant.fund?.parentOrganization?.logo?.title ??
'',
link: {
label: getTranslationString('applicationClosed'),
href: linkResolver(
'styrkjatorggrant',
[grant?.applicationId ?? ''],
activeLocale,
).href,
},
detailLines: [
grant.dateFrom && grant.dateTo
? {
icon: 'calendar' as const,
text: `${format(
new Date(grant.dateFrom),
'dd.MM.yyyy',
)} - ${format(new Date(grant.dateTo), 'dd.MM.yyyy')}`,
}
: null,
grant.status
? {
icon: 'time' as const,
text: parseStatus(grant),
}
: undefined,
grant.categoryTags
? {
icon: 'informationCircle' as const,
text: grant.categoryTags
.map((ct) => ct.title)
.filter(isDefined)
.join(', '),
}
: undefined,
].filter(isDefined),
}
}
return null
})
.filter(isDefined)

return (
<Box padding={1} borderColor="blue100" borderRadius="large">
<InfoCardGrid columns={1} variant="detailed" cards={cards ?? []} />
</Box>
)
}

export default GrantCardsList
5 changes: 5 additions & 0 deletions apps/web/components/GrantCardsList/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import dynamic from 'next/dynamic'

export const GrantCardsList = dynamic(() => import('./GrantCardsList'), {
ssr: true,
})
18 changes: 18 additions & 0 deletions apps/web/components/GrantCardsList/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export type TranslationKeys = Partial<
Record<
| 'seeMore'
| 'apply'
| 'applicationOpen'
| 'applicationClosed'
| 'applicationOpensSoon'
| 'applicationSeeDescription'
| 'applicationOpensAt'
| 'applicationEstimatedOpensAt'
| 'applicationOpensTo'
| 'applicationOpensToWithDay'
| 'applicationWasOpenTo'
| 'applicationWasOpenToAndWith'
| 'applicationAlwaysOpen',
string
>
>
thorkellmani marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion apps/web/components/TableOfContents/TableOfContents.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FC, useMemo } from 'react'

import { Slice } from '@island.is/api/schema'
import { TableOfContents } from '@island.is/island-ui/core'
import { Slice } from '@island.is/web/graphql/schema'
thorkellmani marked this conversation as resolved.
Show resolved Hide resolved
import { scrollTo } from '@island.is/web/hooks/useScrollSpy'

export const TOC: FC<
Expand Down
40 changes: 21 additions & 19 deletions apps/web/screens/Home/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
import React, { useContext } from 'react'
import { Box, GridContainer } from '@island.is/island-ui/core'
import { useI18n } from '@island.is/web/i18n'
import { Screen } from '@island.is/web/types'
import { useNamespace } from '@island.is/web/hooks'

import { Box } from '@island.is/island-ui/core'
import { Locale } from '@island.is/shared/types'
import {
CategoryItems,
LifeEventsSection,
NewsItems,
SearchSection,
WatsonChatPanel,
} from '@island.is/web/components'
import { FRONTPAGE_NEWS_TAG_ID } from '@island.is/web/constants'
import { GlobalContext } from '@island.is/web/context'
import {
ContentLanguage,
QueryGetArticleCategoriesArgs,
GetArticleCategoriesQuery,
GetFrontpageQuery,
QueryGetFrontpageArgs,
GetNewsQuery,
LifeEventPage,
QueryGetArticleCategoriesArgs,
QueryGetFrontpageArgs,
QueryGetNewsArgs,
} from '@island.is/web/graphql/schema'
import { useNamespace } from '@island.is/web/hooks'
import { useI18n } from '@island.is/web/i18n'
import { withMainLayout } from '@island.is/web/layouts/main'
import {
GET_CATEGORIES_QUERY,
GET_FRONTPAGE_QUERY,
GET_NEWS_QUERY,
} from '@island.is/web/screens/queries'
import {
SearchSection,
CategoryItems,
NewLinks,
NewsItems,
LifeEventsSection,
WatsonChatPanel,
} from '@island.is/web/components'
import { withMainLayout } from '@island.is/web/layouts/main'
import { GlobalContext } from '@island.is/web/context'
import { LifeEventPage, QueryGetNewsArgs } from '@island.is/api/schema'
import { FRONTPAGE_NEWS_TAG_ID } from '@island.is/web/constants'
import { Locale } from '@island.is/shared/types'
import { Screen } from '@island.is/web/types'

import { watsonConfig } from './config'

interface HomeProps {
Expand Down
59 changes: 59 additions & 0 deletions apps/web/screens/queries/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,64 @@ export const slices = gql`
aspectRatio
}

fragment GrantCardsListFields on GrantCardsList {
__typename
id
title
displayTitle
namespace
resolvedGrantsList {
total
items {
id
name
description
applicationId
applicationUrl {
slug
type
}
dateFrom
dateTo
status
statusText
categoryTags {
id
title
genericTagGroup {
title
}
}
typeTag {
id
title
genericTagGroup {
title
}
}
fund {
id
title
link {
slug
type
}
featuredImage {
id
url
}
parentOrganization {
id
title
logo {
url
}
}
}
}
}
}

fragment LatestEventsSliceFields on LatestEventsSlice {
title
events {
Expand Down Expand Up @@ -965,6 +1023,7 @@ export const slices = gql`
...FeaturedEventsFields
...GenericListFields
...LatestGenericListItemsFields
...GrantCardsListFields
}

fragment AllSlices on Slice {
Expand Down
5 changes: 5 additions & 0 deletions apps/web/utils/richText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import {
FeaturedSupportQnAs as FeaturedSupportQNAsSchema,
Form as FormSchema,
GenericList as GenericListSchema,
GrantCardsList as GrantCardsListSchema,
MultipleStatistics as MultipleStatisticsSchema,
OneColumnText,
OverviewLinks as OverviewLinksSliceSchema,
Expand All @@ -91,6 +92,7 @@ import { UmsCostOfLivingCalculator } from '../components/connected/UmbodsmadurSk
import { WHODASCalculator } from '../components/connected/WHODAS/Calculator'
import FeaturedEvents from '../components/FeaturedEvents/FeaturedEvents'
import FeaturedSupportQNAs from '../components/FeaturedSupportQNAs/FeaturedSupportQNAs'
import { GrantCardsList } from '../components/GrantCardsList'
import { EmbedSlice } from '../components/Organization/Slice/EmbedSlice/EmbedSlice'

interface TranslationNamespaceProviderProps {
Expand Down Expand Up @@ -290,6 +292,9 @@ const defaultRenderComponent = {
const url = slice?.url ? slice.url + '?w=800' : ''
return <Image {...slice} thumbnail={thumbnailUrl} url={url} />
},
GrantCardsList: (slice: GrantCardsListSchema) => (
<GrantCardsList slice={slice} />
),
}

export const webRichText = (
Expand Down
Loading
Loading