parent
84b5887934
commit
efdd00d2f0
4 changed files with 77 additions and 22 deletions
|
|
@ -36,6 +36,14 @@ export const ImageCardsBlock: Block = {
|
|||
admin: {
|
||||
condition: (_, siblingData) => !siblingData?.customLink,
|
||||
},
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
// Write null instead of undefined so the Postgres adapter removes stale
|
||||
// _rels rows left behind by block reordering, otherwise they resurface
|
||||
// as this card's link: https://github.com/payloadcms/payload/issues/16647
|
||||
({ value, siblingData }) => (siblingData?.customLink ? null : (value ?? null)),
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'customLink',
|
||||
|
|
@ -43,9 +51,8 @@ export const ImageCardsBlock: Block = {
|
|||
type: 'text',
|
||||
required: false,
|
||||
admin: {
|
||||
condition: (_, siblingData) => !siblingData?.link,
|
||||
description:
|
||||
'Alternative zu "Verknüpfung". Nur eins von beiden kann gesetzt werden.',
|
||||
'Alternative zu "Verknüpfung", z.B. für externe Seiten oder PDF-Dokumente.',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
import { Group, Media, Page } from '@/payload-types'
|
||||
import { Media } from '@/payload-types'
|
||||
import { Container } from '@/components/Container/Container'
|
||||
import { Section } from '@/components/Section/Section'
|
||||
import { ImageCard } from '@/components/ImageCard/ImageCard'
|
||||
import { getPhoto } from '@/utils/dto/gallery'
|
||||
import { ImageCardLinkFields, resolveImageCardHref } from '@/utils/dto/imageCardHref'
|
||||
import styles from './imageCardsBlock.module.scss'
|
||||
|
||||
export type ImageCardsBlockItem = {
|
||||
export type ImageCardsBlockItem = ImageCardLinkFields & {
|
||||
title: string
|
||||
image: string | Media
|
||||
link?:
|
||||
| { relationTo: 'pages'; value: string | Page }
|
||||
| { relationTo: 'group'; value: string | Group }
|
||||
| null
|
||||
customLink?: string | null
|
||||
id?: string | null
|
||||
}
|
||||
|
||||
|
|
@ -20,18 +16,6 @@ type ImageCardsBlockProps = {
|
|||
items: ImageCardsBlockItem[]
|
||||
}
|
||||
|
||||
const resolveHref = (item: ImageCardsBlockItem): string | undefined => {
|
||||
if (item.link && typeof item.link.value === 'object') {
|
||||
if (item.link.relationTo === 'pages' && item.link.value.slug) {
|
||||
return `/${item.link.value.slug}`
|
||||
}
|
||||
if (item.link.relationTo === 'group' && item.link.value.slug) {
|
||||
return `/gruppe/${item.link.value.slug}`
|
||||
}
|
||||
}
|
||||
return item.customLink ?? undefined
|
||||
}
|
||||
|
||||
export const ImageCardsBlock = ({ items }: ImageCardsBlockProps) => {
|
||||
return (
|
||||
<Container>
|
||||
|
|
@ -46,7 +30,7 @@ export const ImageCardsBlock = ({ items }: ImageCardsBlockProps) => {
|
|||
key={item.id ?? item.title}
|
||||
src={photo.src}
|
||||
title={item.title}
|
||||
href={resolveHref(item)}
|
||||
href={resolveImageCardHref(item)}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
|
|
|
|||
34
src/utils/dto/imageCardHref.test.ts
Normal file
34
src/utils/dto/imageCardHref.test.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
import { resolveImageCardHref } from './imageCardHref'
|
||||
|
||||
const page = { slug: 'chronik' } as any
|
||||
const group = { slug: 'chor' } as any
|
||||
|
||||
describe('resolveImageCardHref', () => {
|
||||
it('links to a page relationship', () => {
|
||||
expect(resolveImageCardHref({ link: { relationTo: 'pages', value: page } })).toBe('/chronik')
|
||||
})
|
||||
|
||||
it('links to a group relationship', () => {
|
||||
expect(resolveImageCardHref({ link: { relationTo: 'group', value: group } })).toBe('/gruppe/chor')
|
||||
})
|
||||
|
||||
it('returns nothing for an unpopulated relationship', () => {
|
||||
expect(resolveImageCardHref({ link: { relationTo: 'group', value: 'id-only' } })).toBeUndefined()
|
||||
})
|
||||
|
||||
it('uses the custom link when no relationship is set', () => {
|
||||
expect(resolveImageCardHref({ link: null, customLink: 'https://example.org/x.pdf' }))
|
||||
.toBe('https://example.org/x.pdf')
|
||||
})
|
||||
|
||||
it('prefers the custom link when a stale relationship is also present', () => {
|
||||
expect(resolveImageCardHref({ link: { relationTo: 'group', value: group }, customLink: 'https://example.org/x.pdf' }))
|
||||
.toBe('https://example.org/x.pdf')
|
||||
})
|
||||
|
||||
it('ignores a blank custom link', () => {
|
||||
expect(resolveImageCardHref({ link: { relationTo: 'group', value: group }, customLink: ' ' })).toBe('/gruppe/chor')
|
||||
expect(resolveImageCardHref({ customLink: '' })).toBeUndefined()
|
||||
})
|
||||
})
|
||||
30
src/utils/dto/imageCardHref.ts
Normal file
30
src/utils/dto/imageCardHref.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import type { Group, Page } from '@/payload-types'
|
||||
|
||||
export type ImageCardLink =
|
||||
| { relationTo: 'pages'; value: string | Page }
|
||||
| { relationTo: 'group'; value: string | Group }
|
||||
| null
|
||||
|
||||
export type ImageCardLinkFields = {
|
||||
link?: ImageCardLink
|
||||
customLink?: string | null
|
||||
}
|
||||
|
||||
// A custom link wins over the relationship. Both can be present at once when a
|
||||
// stale relationship row survives in the database (see the beforeChange hook in
|
||||
// src/collections/blocks/ImageCards.ts), and the custom link is what the editor
|
||||
// actually sees and intends.
|
||||
export const resolveImageCardHref = (item: ImageCardLinkFields): string | undefined => {
|
||||
const customLink = item.customLink?.trim()
|
||||
if (customLink) return customLink
|
||||
|
||||
if (item.link && typeof item.link.value === 'object') {
|
||||
if (item.link.relationTo === 'pages' && item.link.value.slug) {
|
||||
return `/${item.link.value.slug}`
|
||||
}
|
||||
if (item.link.relationTo === 'group' && item.link.value.slug) {
|
||||
return `/gruppe/${item.link.value.slug}`
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
Loading…
Reference in a new issue