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})