Hooks

Use hooks for data transformation and business logic. Hooks should be placed in a separate file under hooks/{file}.ts within the collection folder and have a test along side it.

Example:

src/collections/{collection}/setConnectedAt.ts

 1export const setConnectedAt: CollectionBeforeChangeHook<Connection> = async (args) => {
 2	const { data, originalDoc } = args
 3
 4	// Only process if status field exists in the data.
 5	if (!data?.status) {
 6		return data
 7	}
 8
 9	// If status is being changed to 'accepted', set the connectedAt timestamp.
10	if (data.status === 'accepted' && originalDoc?.status !== 'accepted') {
11		data.connectedAt = new Date().toISOString()
12	}
13
14	// If status is changed from 'accepted' to something else, clear the connectedAt timestamp.
15	if (data.status !== 'accepted' && originalDoc?.status === 'accepted') {
16		data.connectedAt = null
17	}
18
19	return data
20}

src/collections/{collection}/setConnectedAt.test.ts

 1import { getPayload, Payload } from 'payload'
 2import { describe, it, beforeAll, expect, beforeEach } from 'vitest'
 3
 4import config from '@/payload.config'
 5import { createTestPlayer } from '@/test/fixtures'
 6import { teardown } from '@/test/util'
 7
 8let payload: Payload
 9
10describe('setConnectedAt hook', () => {
11	beforeAll(async () => {
12		const payloadConfig = await config
13		payload = await getPayload({ config: payloadConfig })
14	})
15
16	beforeEach(async () => {
17		await teardown(payload)
18	})
19
20	it('Sets connectedAt timestamp when connection is accepted', async () => {
21		const player1 = await createTestPlayer(payload)
22		const player2 = await createTestPlayer(payload)
23
24		const connection = await payload.create({
25			collection: 'connections',
26			data: {
27				requester: player1.id,
28				recipient: player2.id,
29				status: 'pending',
30			},
31		})
32
33		// Initially should not have connectedAt.
34		expect(connection.connectedAt).toBeFalsy()
35
36		// Update to accepted status.
37		const updated = await payload.update({
38			collection: 'connections',
39			id: connection.id,
40			data: {
41				status: 'accepted',
42			},
43		})
44
45		// Should now have connectedAt timestamp.
46		expect(updated.connectedAt).toBeDefined()
47		expect(typeof updated.connectedAt).toBe('string')
48	})
49})
Last modified: 27/10/2025 2022-2025 ©ainsley.dev, All rights reserved.