parent
84b5887934
commit
efdd00d2f0
4 changed files with 77 additions and 22 deletions
|
|
@ -36,6 +36,14 @@ export const ImageCardsBlock: Block = {
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) => !siblingData?.customLink,
|
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',
|
name: 'customLink',
|
||||||
|
|
@ -43,9 +51,8 @@ export const ImageCardsBlock: Block = {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
required: false,
|
required: false,
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) => !siblingData?.link,
|
|
||||||
description:
|
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 { Container } from '@/components/Container/Container'
|
||||||
import { Section } from '@/components/Section/Section'
|
import { Section } from '@/components/Section/Section'
|
||||||
import { ImageCard } from '@/components/ImageCard/ImageCard'
|
import { ImageCard } from '@/components/ImageCard/ImageCard'
|
||||||
import { getPhoto } from '@/utils/dto/gallery'
|
import { getPhoto } from '@/utils/dto/gallery'
|
||||||
|
import { ImageCardLinkFields, resolveImageCardHref } from '@/utils/dto/imageCardHref'
|
||||||
import styles from './imageCardsBlock.module.scss'
|
import styles from './imageCardsBlock.module.scss'
|
||||||
|
|
||||||
export type ImageCardsBlockItem = {
|
export type ImageCardsBlockItem = ImageCardLinkFields & {
|
||||||
title: string
|
title: string
|
||||||
image: string | Media
|
image: string | Media
|
||||||
link?:
|
|
||||||
| { relationTo: 'pages'; value: string | Page }
|
|
||||||
| { relationTo: 'group'; value: string | Group }
|
|
||||||
| null
|
|
||||||
customLink?: string | null
|
|
||||||
id?: string | null
|
id?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,18 +16,6 @@ type ImageCardsBlockProps = {
|
||||||
items: ImageCardsBlockItem[]
|
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) => {
|
export const ImageCardsBlock = ({ items }: ImageCardsBlockProps) => {
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
|
|
@ -46,7 +30,7 @@ export const ImageCardsBlock = ({ items }: ImageCardsBlockProps) => {
|
||||||
key={item.id ?? item.title}
|
key={item.id ?? item.title}
|
||||||
src={photo.src}
|
src={photo.src}
|
||||||
title={item.title}
|
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