@sanity/sdk-react 0.0.0-alpha.19 → 0.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -38
- package/dist/_chunks-es/useLogOut.js +44 -0
- package/dist/_chunks-es/useLogOut.js.map +1 -0
- package/dist/assets/bundle-CcAyERuZ.css +11 -0
- package/dist/components.d.ts +257 -0
- package/dist/components.js +316 -0
- package/dist/components.js.map +1 -0
- package/dist/hooks.d.ts +187 -0
- package/dist/hooks.js +81 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +2 -4641
- package/dist/index.js +2 -960
- package/dist/index.js.map +1 -1
- package/package.json +56 -25
- package/src/_exports/components.ts +13 -0
- package/src/_exports/hooks.ts +9 -0
- package/src/_exports/index.ts +10 -58
- package/src/components/DocumentGridLayout/DocumentGridLayout.stories.tsx +113 -0
- package/src/components/DocumentGridLayout/DocumentGridLayout.test.tsx +42 -0
- package/src/components/DocumentGridLayout/DocumentGridLayout.tsx +21 -0
- package/src/components/DocumentListLayout/DocumentListLayout.stories.tsx +105 -0
- package/src/components/DocumentListLayout/DocumentListLayout.test.tsx +42 -0
- package/src/components/DocumentListLayout/DocumentListLayout.tsx +12 -0
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.md +49 -0
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.stories.tsx +39 -0
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.test.tsx +30 -0
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.tsx +171 -0
- package/src/components/Login/LoginLinks.test.tsx +12 -2
- package/src/components/Login/LoginLinks.tsx +29 -14
- package/src/components/auth/AuthBoundary.test.tsx +17 -4
- package/src/components/auth/AuthBoundary.tsx +4 -20
- package/src/components/auth/Login.test.tsx +16 -2
- package/src/components/auth/Login.tsx +30 -11
- package/src/components/auth/LoginCallback.test.tsx +17 -2
- package/src/components/auth/LoginCallback.tsx +10 -5
- package/src/components/auth/LoginError.test.tsx +17 -2
- package/src/components/auth/LoginError.tsx +16 -11
- package/src/components/auth/LoginFooter.test.tsx +16 -2
- package/src/components/auth/LoginFooter.tsx +24 -8
- package/src/components/auth/LoginLayout.test.tsx +16 -2
- package/src/components/auth/LoginLayout.tsx +38 -8
- package/src/{context → components/context}/SanityProvider.test.tsx +2 -2
- package/src/components/context/SanityProvider.tsx +42 -0
- package/src/css/css.config.js +220 -0
- package/src/css/paramour.css +2347 -0
- package/src/css/styles.css +11 -0
- package/src/hooks/auth/useAuthState.tsx +5 -4
- package/src/hooks/auth/useAuthToken.tsx +1 -1
- package/src/hooks/auth/useCurrentUser.tsx +4 -27
- package/src/hooks/auth/useHandleCallback.tsx +0 -1
- package/src/hooks/auth/useLogOut.tsx +1 -1
- package/src/hooks/auth/useLoginUrls.tsx +0 -1
- package/src/hooks/client/useClient.test.tsx +130 -0
- package/src/hooks/client/useClient.ts +30 -8
- package/src/hooks/context/useSanityInstance.test.tsx +2 -2
- package/src/hooks/context/useSanityInstance.ts +8 -24
- package/src/hooks/documentCollection/useDocuments.test.ts +130 -0
- package/src/hooks/documentCollection/useDocuments.ts +87 -0
- package/src/hooks/helpers/createCallbackHook.tsx +2 -3
- package/src/hooks/helpers/createStateSourceHook.test.tsx +0 -66
- package/src/hooks/helpers/createStateSourceHook.tsx +10 -29
- package/src/hooks/preview/usePreview.test.tsx +10 -19
- package/src/hooks/preview/usePreview.tsx +13 -67
- package/src/components/SDKProvider.test.tsx +0 -79
- package/src/components/SDKProvider.tsx +0 -42
- package/src/components/SanityApp.test.tsx +0 -156
- package/src/components/SanityApp.tsx +0 -90
- package/src/components/auth/authTestHelpers.tsx +0 -11
- package/src/components/utils.ts +0 -22
- package/src/context/SanityInstanceContext.ts +0 -4
- package/src/context/SanityProvider.tsx +0 -50
- package/src/hooks/_synchronous-groq-js.mjs +0 -4
- package/src/hooks/comlink/useFrameConnection.test.tsx +0 -157
- package/src/hooks/comlink/useFrameConnection.ts +0 -130
- package/src/hooks/comlink/useManageFavorite.test.ts +0 -106
- package/src/hooks/comlink/useManageFavorite.ts +0 -98
- package/src/hooks/comlink/useRecordDocumentHistoryEvent.test.ts +0 -77
- package/src/hooks/comlink/useRecordDocumentHistoryEvent.ts +0 -75
- package/src/hooks/comlink/useWindowConnection.test.ts +0 -125
- package/src/hooks/comlink/useWindowConnection.ts +0 -94
- package/src/hooks/datasets/useDatasets.ts +0 -37
- package/src/hooks/document/useApplyActions.test.ts +0 -25
- package/src/hooks/document/useApplyActions.ts +0 -74
- package/src/hooks/document/useDocument.test.ts +0 -81
- package/src/hooks/document/useDocument.ts +0 -107
- package/src/hooks/document/useDocumentEvent.test.ts +0 -63
- package/src/hooks/document/useDocumentEvent.ts +0 -54
- package/src/hooks/document/useDocumentSyncStatus.test.ts +0 -16
- package/src/hooks/document/useDocumentSyncStatus.ts +0 -30
- package/src/hooks/document/useEditDocument.test.ts +0 -179
- package/src/hooks/document/useEditDocument.ts +0 -195
- package/src/hooks/document/usePermissions.ts +0 -82
- package/src/hooks/infiniteList/useInfiniteList.test.tsx +0 -152
- package/src/hooks/infiniteList/useInfiniteList.ts +0 -174
- package/src/hooks/paginatedList/usePaginatedList.test.tsx +0 -259
- package/src/hooks/paginatedList/usePaginatedList.ts +0 -290
- package/src/hooks/projection/useProjection.test.tsx +0 -218
- package/src/hooks/projection/useProjection.ts +0 -135
- package/src/hooks/projects/useProject.ts +0 -45
- package/src/hooks/projects/useProjects.ts +0 -41
- package/src/hooks/query/useQuery.test.tsx +0 -188
- package/src/hooks/query/useQuery.ts +0 -103
- package/src/hooks/users/useUsers.test.ts +0 -163
- package/src/hooks/users/useUsers.ts +0 -107
- package/src/utils/getEnv.ts +0 -21
- package/src/version.ts +0 -8
- package/src/vite-env.d.ts +0 -10
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import {act, renderHook} from '@testing-library/react'
|
|
2
|
-
import {describe, vi} from 'vitest'
|
|
3
|
-
|
|
4
|
-
import {evaluateSync, parse} from '../_synchronous-groq-js.mjs'
|
|
5
|
-
import {useQuery} from '../query/useQuery'
|
|
6
|
-
import {useInfiniteList} from './useInfiniteList'
|
|
7
|
-
|
|
8
|
-
vi.mock('../query/useQuery')
|
|
9
|
-
|
|
10
|
-
describe('useInfiniteList', () => {
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
const dataset = [
|
|
13
|
-
{
|
|
14
|
-
_id: 'movie1',
|
|
15
|
-
_type: 'movie',
|
|
16
|
-
title: 'The Matrix',
|
|
17
|
-
releaseYear: 1999,
|
|
18
|
-
_createdAt: '2021-03-09T00:00:00.000Z',
|
|
19
|
-
_updatedAt: '2021-03-09T00:00:00.000Z',
|
|
20
|
-
_rev: 'tx0',
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
_id: 'movie2',
|
|
24
|
-
_type: 'movie',
|
|
25
|
-
title: 'Inception',
|
|
26
|
-
releaseYear: 2010,
|
|
27
|
-
_createdAt: '2021-03-10T00:00:00.000Z',
|
|
28
|
-
_updatedAt: '2021-03-10T00:00:00.000Z',
|
|
29
|
-
_rev: 'tx1',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
_id: 'movie3',
|
|
33
|
-
_type: 'movie',
|
|
34
|
-
title: 'Interstellar',
|
|
35
|
-
releaseYear: 2014,
|
|
36
|
-
_createdAt: '2021-03-11T00:00:00.000Z',
|
|
37
|
-
_updatedAt: '2021-03-11T00:00:00.000Z',
|
|
38
|
-
_rev: 'tx2',
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
_id: 'book1',
|
|
42
|
-
_type: 'book',
|
|
43
|
-
title: 'Dune',
|
|
44
|
-
_createdAt: '2021-03-12T00:00:00.000Z',
|
|
45
|
-
_updatedAt: '2021-03-12T00:00:00.000Z',
|
|
46
|
-
_rev: 'tx3',
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
_id: 'movie4',
|
|
50
|
-
_type: 'movie',
|
|
51
|
-
title: 'The Dark Knight',
|
|
52
|
-
releaseYear: 2008,
|
|
53
|
-
_createdAt: '2021-03-13T00:00:00.000Z',
|
|
54
|
-
_updatedAt: '2021-03-13T00:00:00.000Z',
|
|
55
|
-
_rev: 'tx4',
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
_id: 'movie5',
|
|
59
|
-
_type: 'movie',
|
|
60
|
-
title: 'Pulp Fiction',
|
|
61
|
-
releaseYear: 1994,
|
|
62
|
-
_createdAt: '2021-03-14T00:00:00.000Z',
|
|
63
|
-
_updatedAt: '2021-03-14T00:00:00.000Z',
|
|
64
|
-
_rev: 'tx5',
|
|
65
|
-
},
|
|
66
|
-
]
|
|
67
|
-
|
|
68
|
-
vi.mocked(useQuery).mockImplementation((query, options) => {
|
|
69
|
-
const result = evaluateSync(parse(query), {dataset, params: options?.params}).get()
|
|
70
|
-
return {
|
|
71
|
-
data: result,
|
|
72
|
-
isPending: false,
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('should respect custom page size', () => {
|
|
78
|
-
const customBatchSize = 2
|
|
79
|
-
const {result} = renderHook(() => useInfiniteList({batchSize: customBatchSize}))
|
|
80
|
-
|
|
81
|
-
expect(result.current.data.length).toBe(customBatchSize)
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
it('should filter by document type', () => {
|
|
85
|
-
const {result} = renderHook(() => useInfiniteList({filter: '_type == "movie"'}))
|
|
86
|
-
|
|
87
|
-
expect(result.current.data.every((doc) => doc._type === 'movie')).toBe(true)
|
|
88
|
-
expect(result.current.count).toBe(5) // 5 movies in the dataset
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// groq-js doesn't support search filters yet
|
|
92
|
-
it.skip('should apply search filter', () => {
|
|
93
|
-
const {result} = renderHook(() => useInfiniteList({search: 'inter'}))
|
|
94
|
-
|
|
95
|
-
// Should match "Interstellar"
|
|
96
|
-
expect(result.current.data.some((doc) => doc._id === 'movie3')).toBe(true)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('should apply ordering', () => {
|
|
100
|
-
const {result} = renderHook(() =>
|
|
101
|
-
useInfiniteList({
|
|
102
|
-
filter: '_type == "movie"',
|
|
103
|
-
orderings: [{field: 'releaseYear', direction: 'desc'}],
|
|
104
|
-
}),
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
// First item should be the most recent movie (Interstellar, 2014)
|
|
108
|
-
expect(result.current.data[0]._id).toBe('movie3')
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
it('should load more data when loadMore is called', () => {
|
|
112
|
-
const batchSize = 2
|
|
113
|
-
const {result} = renderHook(() => useInfiniteList({batchSize: batchSize}))
|
|
114
|
-
|
|
115
|
-
expect(result.current.data.length).toBe(batchSize)
|
|
116
|
-
|
|
117
|
-
act(() => {
|
|
118
|
-
result.current.loadMore()
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
expect(result.current.data.length).toBe(batchSize * 2)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('should indicate when there is more data to load', () => {
|
|
125
|
-
const {result} = renderHook(() => useInfiniteList({batchSize: 3}))
|
|
126
|
-
expect(result.current.hasMore).toBe(true)
|
|
127
|
-
// Load all remaining data
|
|
128
|
-
act(() => {
|
|
129
|
-
result.current.loadMore()
|
|
130
|
-
})
|
|
131
|
-
expect(result.current.hasMore).toBe(false)
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
// New test case for resetting limit when filter changes
|
|
135
|
-
it('should reset limit when filter changes', () => {
|
|
136
|
-
const {result, rerender} = renderHook((props) => useInfiniteList(props), {
|
|
137
|
-
initialProps: {batchSize: 2, filter: ''},
|
|
138
|
-
})
|
|
139
|
-
// Initially, data length equals pageSize (2)
|
|
140
|
-
expect(result.current.data.length).toBe(2)
|
|
141
|
-
// Load more to increase limit
|
|
142
|
-
act(() => {
|
|
143
|
-
result.current.loadMore()
|
|
144
|
-
})
|
|
145
|
-
// After loadMore, data length should be increased (2 + 2 = 4)
|
|
146
|
-
expect(result.current.data.length).toBe(4)
|
|
147
|
-
// Now update filter to trigger resetting the limit
|
|
148
|
-
rerender({batchSize: 2, filter: '_type == "movie"'})
|
|
149
|
-
// With the filter applied, the limit is reset to pageSize (i.e. 2)
|
|
150
|
-
expect(result.current.data.length).toBe(2)
|
|
151
|
-
})
|
|
152
|
-
})
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import {type DocumentHandle, type QueryOptions} from '@sanity/sdk'
|
|
2
|
-
import {type SortOrderingItem} from '@sanity/types'
|
|
3
|
-
import {useCallback, useEffect, useMemo, useState} from 'react'
|
|
4
|
-
|
|
5
|
-
import {useQuery} from '../query/useQuery'
|
|
6
|
-
|
|
7
|
-
const DEFAULT_BATCH_SIZE = 25
|
|
8
|
-
const DEFAULT_PERSPECTIVE = 'drafts'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Result structure returned from the infinite list query
|
|
12
|
-
* @internal
|
|
13
|
-
*/
|
|
14
|
-
interface InfiniteListQueryResult {
|
|
15
|
-
count: number
|
|
16
|
-
data: DocumentHandle[]
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Configuration options for the useInfiniteList hook
|
|
21
|
-
*
|
|
22
|
-
* @beta
|
|
23
|
-
* @category Types
|
|
24
|
-
*/
|
|
25
|
-
export interface InfiniteListOptions extends QueryOptions {
|
|
26
|
-
/**
|
|
27
|
-
* GROQ filter expression to apply to the query
|
|
28
|
-
*/
|
|
29
|
-
filter?: string
|
|
30
|
-
/**
|
|
31
|
-
* Number of items to load per batch (defaults to 25)
|
|
32
|
-
*/
|
|
33
|
-
batchSize?: number
|
|
34
|
-
/**
|
|
35
|
-
* Sorting configuration for the results
|
|
36
|
-
*/
|
|
37
|
-
orderings?: SortOrderingItem[]
|
|
38
|
-
/**
|
|
39
|
-
* Text search query to filter results
|
|
40
|
-
*/
|
|
41
|
-
search?: string
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Return value from the useInfiniteList hook
|
|
46
|
-
*
|
|
47
|
-
* @beta
|
|
48
|
-
* @category Types
|
|
49
|
-
*/
|
|
50
|
-
export interface InfiniteList {
|
|
51
|
-
/**
|
|
52
|
-
* Array of document handles for the current batch
|
|
53
|
-
*/
|
|
54
|
-
data: DocumentHandle[]
|
|
55
|
-
/**
|
|
56
|
-
* Whether there are more items available to load
|
|
57
|
-
*/
|
|
58
|
-
hasMore: boolean
|
|
59
|
-
/**
|
|
60
|
-
* Total count of items matching the query
|
|
61
|
-
*/
|
|
62
|
-
count: number
|
|
63
|
-
/**
|
|
64
|
-
* Whether a query is currently in progress
|
|
65
|
-
*/
|
|
66
|
-
isPending: boolean
|
|
67
|
-
/**
|
|
68
|
-
* Function to load the next batch of results
|
|
69
|
-
*/
|
|
70
|
-
loadMore: () => void
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Retrieves batches of {@link DocumentHandle}s, narrowed by optional filters, text searches, and custom ordering,
|
|
75
|
-
* with infinite scrolling support. The number of document handles returned per batch is customizable,
|
|
76
|
-
* and additional batches can be loaded using the supplied `loadMore` function.
|
|
77
|
-
*
|
|
78
|
-
* @beta
|
|
79
|
-
* @category Documents
|
|
80
|
-
* @param options - Configuration options for the infinite list
|
|
81
|
-
* @returns An object containing the list of document handles, the loading state, the total count of retrived document handles, and a function to load more
|
|
82
|
-
* @example
|
|
83
|
-
* ```tsx
|
|
84
|
-
* const {data, hasMore, isPending, loadMore} = useInfiniteList({
|
|
85
|
-
* filter: '_type == "post"',
|
|
86
|
-
* search: searchTerm,
|
|
87
|
-
* batchSize: 10,
|
|
88
|
-
* orderings: [{field: '_createdAt', direction: 'desc'}]
|
|
89
|
-
* })
|
|
90
|
-
*
|
|
91
|
-
* return (
|
|
92
|
-
* <div>
|
|
93
|
-
* Total documents: {count}
|
|
94
|
-
* <ol>
|
|
95
|
-
* {data.map((doc) => (
|
|
96
|
-
* <li key={doc._id}>
|
|
97
|
-
* <MyDocumentComponent doc={doc} />
|
|
98
|
-
* </li>
|
|
99
|
-
* ))}
|
|
100
|
-
* </ol>
|
|
101
|
-
* {hasMore && <button onClick={loadMore}>Load More</button>}
|
|
102
|
-
* </div>
|
|
103
|
-
* )
|
|
104
|
-
* ```
|
|
105
|
-
*
|
|
106
|
-
*/
|
|
107
|
-
export function useInfiniteList({
|
|
108
|
-
batchSize = DEFAULT_BATCH_SIZE,
|
|
109
|
-
params,
|
|
110
|
-
search,
|
|
111
|
-
filter,
|
|
112
|
-
orderings,
|
|
113
|
-
...options
|
|
114
|
-
}: InfiniteListOptions): InfiniteList {
|
|
115
|
-
const perspective = options.perspective ?? DEFAULT_PERSPECTIVE
|
|
116
|
-
const [limit, setLimit] = useState(batchSize)
|
|
117
|
-
|
|
118
|
-
// Reset the limit to the current batchSize whenever any query parameters
|
|
119
|
-
// (filter, search, params, orderings) or batchSize changes
|
|
120
|
-
const key = JSON.stringify({filter, search, params, orderings, batchSize})
|
|
121
|
-
useEffect(() => {
|
|
122
|
-
setLimit(batchSize)
|
|
123
|
-
}, [key, batchSize])
|
|
124
|
-
|
|
125
|
-
const filterClause = useMemo(() => {
|
|
126
|
-
const conditions: string[] = []
|
|
127
|
-
|
|
128
|
-
// Add search query if specified
|
|
129
|
-
if (search?.trim()) {
|
|
130
|
-
conditions.push(`[@] match text::query("${search.trim()}")`)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Add additional filter if specified
|
|
134
|
-
if (filter) {
|
|
135
|
-
conditions.push(`(${filter})`)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return conditions.length ? `[${conditions.join(' && ')}]` : ''
|
|
139
|
-
}, [filter, search])
|
|
140
|
-
|
|
141
|
-
const orderClause = orderings
|
|
142
|
-
? `| order(${orderings
|
|
143
|
-
.map((ordering) =>
|
|
144
|
-
[ordering.field, ordering.direction.toLowerCase()]
|
|
145
|
-
.map((str) => str.trim())
|
|
146
|
-
.filter(Boolean)
|
|
147
|
-
.join(' '),
|
|
148
|
-
)
|
|
149
|
-
.join(',')})`
|
|
150
|
-
: ''
|
|
151
|
-
|
|
152
|
-
const dataQuery = `*${filterClause}${orderClause}[0...${limit}]{_id,_type}`
|
|
153
|
-
const countQuery = `count(*${filterClause})`
|
|
154
|
-
|
|
155
|
-
const {
|
|
156
|
-
data: {count, data},
|
|
157
|
-
isPending,
|
|
158
|
-
} = useQuery<InfiniteListQueryResult>(`{"count":${countQuery},"data":${dataQuery}}`, {
|
|
159
|
-
...options,
|
|
160
|
-
params,
|
|
161
|
-
perspective,
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
const hasMore = data.length < count
|
|
165
|
-
|
|
166
|
-
const loadMore = useCallback(() => {
|
|
167
|
-
setLimit((prev) => Math.min(prev + batchSize, count))
|
|
168
|
-
}, [count, batchSize])
|
|
169
|
-
|
|
170
|
-
return useMemo(
|
|
171
|
-
() => ({data, hasMore, count, isPending, loadMore}),
|
|
172
|
-
[data, hasMore, count, isPending, loadMore],
|
|
173
|
-
)
|
|
174
|
-
}
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import {act, renderHook} from '@testing-library/react'
|
|
2
|
-
import {describe, vi} from 'vitest'
|
|
3
|
-
|
|
4
|
-
import {evaluateSync, parse} from '../_synchronous-groq-js.mjs'
|
|
5
|
-
import {useQuery} from '../query/useQuery'
|
|
6
|
-
import {usePaginatedList} from './usePaginatedList'
|
|
7
|
-
|
|
8
|
-
vi.mock('../query/useQuery')
|
|
9
|
-
|
|
10
|
-
describe('usePaginatedList', () => {
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
const dataset = [
|
|
13
|
-
{
|
|
14
|
-
_id: 'movie1',
|
|
15
|
-
_type: 'movie',
|
|
16
|
-
title: 'The Matrix',
|
|
17
|
-
releaseYear: 1999,
|
|
18
|
-
_createdAt: '2021-03-09T00:00:00.000Z',
|
|
19
|
-
_updatedAt: '2021-03-09T00:00:00.000Z',
|
|
20
|
-
_rev: 'tx0',
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
_id: 'movie2',
|
|
24
|
-
_type: 'movie',
|
|
25
|
-
title: 'Inception',
|
|
26
|
-
releaseYear: 2010,
|
|
27
|
-
_createdAt: '2021-03-10T00:00:00.000Z',
|
|
28
|
-
_updatedAt: '2021-03-10T00:00:00.000Z',
|
|
29
|
-
_rev: 'tx1',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
_id: 'movie3',
|
|
33
|
-
_type: 'movie',
|
|
34
|
-
title: 'Interstellar',
|
|
35
|
-
releaseYear: 2014,
|
|
36
|
-
_createdAt: '2021-03-11T00:00:00.000Z',
|
|
37
|
-
_updatedAt: '2021-03-11T00:00:00.000Z',
|
|
38
|
-
_rev: 'tx2',
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
_id: 'book1',
|
|
42
|
-
_type: 'book',
|
|
43
|
-
title: 'Dune',
|
|
44
|
-
_createdAt: '2021-03-12T00:00:00.000Z',
|
|
45
|
-
_updatedAt: '2021-03-12T00:00:00.000Z',
|
|
46
|
-
_rev: 'tx3',
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
_id: 'movie4',
|
|
50
|
-
_type: 'movie',
|
|
51
|
-
title: 'The Dark Knight',
|
|
52
|
-
releaseYear: 2008,
|
|
53
|
-
_createdAt: '2021-03-13T00:00:00.000Z',
|
|
54
|
-
_updatedAt: '2021-03-13T00:00:00.000Z',
|
|
55
|
-
_rev: 'tx4',
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
_id: 'movie5',
|
|
59
|
-
_type: 'movie',
|
|
60
|
-
title: 'Pulp Fiction',
|
|
61
|
-
releaseYear: 1994,
|
|
62
|
-
_createdAt: '2021-03-14T00:00:00.000Z',
|
|
63
|
-
_updatedAt: '2021-03-14T00:00:00.000Z',
|
|
64
|
-
_rev: 'tx5',
|
|
65
|
-
},
|
|
66
|
-
]
|
|
67
|
-
|
|
68
|
-
vi.mocked(useQuery).mockImplementation((query, options) => {
|
|
69
|
-
const result = evaluateSync(parse(query), {dataset, params: options?.params}).get()
|
|
70
|
-
return {
|
|
71
|
-
data: result,
|
|
72
|
-
isPending: false,
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('should respect custom page size', () => {
|
|
78
|
-
const customPageSize = 2
|
|
79
|
-
const {result} = renderHook(() => usePaginatedList({pageSize: customPageSize}))
|
|
80
|
-
|
|
81
|
-
expect(result.current.pageSize).toBe(customPageSize)
|
|
82
|
-
expect(result.current.data.length).toBeLessThanOrEqual(customPageSize)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('should filter by document type', () => {
|
|
86
|
-
const {result} = renderHook(() => usePaginatedList({filter: '_type == "movie"'}))
|
|
87
|
-
|
|
88
|
-
expect(result.current.data.every((doc) => doc._type === 'movie')).toBe(true)
|
|
89
|
-
expect(result.current.count).toBe(5) // 5 movies in the dataset
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
// groq-js doesn't support search filters yet
|
|
93
|
-
it.skip('should apply search filter', () => {
|
|
94
|
-
const {result} = renderHook(() => usePaginatedList({search: 'inter'}))
|
|
95
|
-
|
|
96
|
-
// Should match "Interstellar"
|
|
97
|
-
expect(result.current.data.some((doc) => doc._id === 'movie3')).toBe(true)
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
it('should apply ordering', () => {
|
|
101
|
-
const {result} = renderHook(() =>
|
|
102
|
-
usePaginatedList({
|
|
103
|
-
filter: '_type == "movie"',
|
|
104
|
-
orderings: [{field: 'releaseYear', direction: 'desc'}],
|
|
105
|
-
}),
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
// First item should be the most recent movie (Interstellar, 2014)
|
|
109
|
-
expect(result.current.data[0]._id).toBe('movie3')
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it('should calculate pagination values correctly', () => {
|
|
113
|
-
const pageSize = 2
|
|
114
|
-
const {result} = renderHook(() => usePaginatedList({pageSize}))
|
|
115
|
-
|
|
116
|
-
expect(result.current.currentPage).toBe(1)
|
|
117
|
-
expect(result.current.totalPages).toBe(3) // 6 items with page size 2
|
|
118
|
-
expect(result.current.startIndex).toBe(0)
|
|
119
|
-
expect(result.current.endIndex).toBe(2)
|
|
120
|
-
expect(result.current.count).toBe(6)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('should navigate to next page', () => {
|
|
124
|
-
const pageSize = 2
|
|
125
|
-
const {result} = renderHook(() => usePaginatedList({pageSize}))
|
|
126
|
-
|
|
127
|
-
expect(result.current.currentPage).toBe(1)
|
|
128
|
-
expect(result.current.data.length).toBe(pageSize)
|
|
129
|
-
|
|
130
|
-
act(() => {
|
|
131
|
-
result.current.nextPage()
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
expect(result.current.currentPage).toBe(2)
|
|
135
|
-
expect(result.current.startIndex).toBe(pageSize)
|
|
136
|
-
expect(result.current.endIndex).toBe(pageSize * 2)
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
it('should navigate to previous page', () => {
|
|
140
|
-
const pageSize = 2
|
|
141
|
-
const {result} = renderHook(() => usePaginatedList({pageSize}))
|
|
142
|
-
|
|
143
|
-
// Go to page 2 first
|
|
144
|
-
act(() => {
|
|
145
|
-
result.current.nextPage()
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
expect(result.current.currentPage).toBe(2)
|
|
149
|
-
|
|
150
|
-
// Then go back to page 1
|
|
151
|
-
act(() => {
|
|
152
|
-
result.current.previousPage()
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
expect(result.current.currentPage).toBe(1)
|
|
156
|
-
expect(result.current.startIndex).toBe(0)
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
it('should navigate to first page', () => {
|
|
160
|
-
const pageSize = 2
|
|
161
|
-
const {result} = renderHook(() => usePaginatedList({pageSize}))
|
|
162
|
-
|
|
163
|
-
// Go to last page first
|
|
164
|
-
act(() => {
|
|
165
|
-
result.current.lastPage()
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
expect(result.current.currentPage).toBe(3) // Last page (3rd page)
|
|
169
|
-
|
|
170
|
-
// Then go back to first page
|
|
171
|
-
act(() => {
|
|
172
|
-
result.current.firstPage()
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
expect(result.current.currentPage).toBe(1)
|
|
176
|
-
expect(result.current.startIndex).toBe(0)
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
it('should navigate to last page', () => {
|
|
180
|
-
const pageSize = 2
|
|
181
|
-
const {result} = renderHook(() => usePaginatedList({pageSize}))
|
|
182
|
-
|
|
183
|
-
act(() => {
|
|
184
|
-
result.current.lastPage()
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
expect(result.current.currentPage).toBe(3) // Last page (3rd page)
|
|
188
|
-
expect(result.current.startIndex).toBe(4) // Index 4-5 for the last page
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
it('should navigate to specific page', () => {
|
|
192
|
-
const pageSize = 2
|
|
193
|
-
const {result} = renderHook(() => usePaginatedList({pageSize}))
|
|
194
|
-
|
|
195
|
-
act(() => {
|
|
196
|
-
result.current.goToPage(2) // Go to page 2
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
expect(result.current.currentPage).toBe(2)
|
|
200
|
-
expect(result.current.startIndex).toBe(2) // Index 2-3 for page 2
|
|
201
|
-
|
|
202
|
-
// Should not navigate to invalid page numbers
|
|
203
|
-
act(() => {
|
|
204
|
-
result.current.goToPage(0) // Invalid page
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
expect(result.current.currentPage).toBe(2) // Should remain on page 2
|
|
208
|
-
|
|
209
|
-
act(() => {
|
|
210
|
-
result.current.goToPage(10) // Invalid page
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
expect(result.current.currentPage).toBe(2) // Should remain on page 2
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
it('should set page availability flags correctly', () => {
|
|
217
|
-
const pageSize = 2
|
|
218
|
-
const {result} = renderHook(() => usePaginatedList({pageSize}))
|
|
219
|
-
// On first page
|
|
220
|
-
expect(result.current.hasFirstPage).toBe(false)
|
|
221
|
-
expect(result.current.hasPreviousPage).toBe(false)
|
|
222
|
-
expect(result.current.hasNextPage).toBe(true)
|
|
223
|
-
expect(result.current.hasLastPage).toBe(true)
|
|
224
|
-
// Go to middle page
|
|
225
|
-
act(() => {
|
|
226
|
-
result.current.nextPage()
|
|
227
|
-
})
|
|
228
|
-
expect(result.current.hasFirstPage).toBe(true)
|
|
229
|
-
expect(result.current.hasPreviousPage).toBe(true)
|
|
230
|
-
expect(result.current.hasNextPage).toBe(true)
|
|
231
|
-
expect(result.current.hasLastPage).toBe(true)
|
|
232
|
-
// Go to last page
|
|
233
|
-
act(() => {
|
|
234
|
-
result.current.lastPage()
|
|
235
|
-
})
|
|
236
|
-
expect(result.current.hasFirstPage).toBe(true)
|
|
237
|
-
expect(result.current.hasPreviousPage).toBe(true)
|
|
238
|
-
expect(result.current.hasNextPage).toBe(false)
|
|
239
|
-
expect(result.current.hasLastPage).toBe(false)
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
// New test case for resetting the current page when filter changes
|
|
243
|
-
it('should reset current page when filter changes', () => {
|
|
244
|
-
const {result, rerender} = renderHook((props) => usePaginatedList(props), {
|
|
245
|
-
initialProps: {pageSize: 2, filter: ''},
|
|
246
|
-
})
|
|
247
|
-
// Initially, current page should be 1
|
|
248
|
-
expect(result.current.currentPage).toBe(1)
|
|
249
|
-
// Navigate to next page
|
|
250
|
-
act(() => {
|
|
251
|
-
result.current.nextPage()
|
|
252
|
-
})
|
|
253
|
-
expect(result.current.currentPage).toBe(2)
|
|
254
|
-
// Now update filter, which should reset the page to the first page
|
|
255
|
-
rerender({pageSize: 2, filter: '_type == "movie"'})
|
|
256
|
-
expect(result.current.currentPage).toBe(1)
|
|
257
|
-
expect(result.current.startIndex).toBe(0)
|
|
258
|
-
})
|
|
259
|
-
})
|