Skip to content

Commit 6ff47de

Browse files
authored
feat(core): add pagination to getVersions endpoint
* feat(ui): add bible reader settings to the bibler reader - refactor popover component to have consistent styling across multiple components and reduce duplication in code. - add bible reader settings and save the users settings to localStorage. * test(ui): add interaction test for the bible reader settings * refactor(ui): namespace the localStorage and limit font size - add a min and max fontSize for the BibleReader - add youversion-platform:reader:* namespacing for reader settings * feat(core): add pagination to getVersions endpoint - update tests to ensure that proper amount of responses are returned based on the page_size query param. - add the ability to specify a page_size to fetch a specific number of items at a time. * refactor(ui): add constants for font sizes on bible reader
1 parent 55ccd98 commit 6ff47de

File tree

6 files changed

+83
-13
lines changed

6 files changed

+83
-13
lines changed

.changeset/clear-pigs-vanish.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@youversion/platform-core': minor
3+
'@youversion/platform-react-ui': minor
4+
'@youversion/platform-react-hooks': minor
5+
---
6+
7+
feat(core): add pagination to the getVersions endpoint
8+
9+
- update tests to ensure that proper amount of responses are returned
10+
based on the page_size query param.
11+
- add the ability to specify a page_size to fetch a specific number of
12+
items at a time.

packages/core/src/__tests__/MockBibles.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ const baseBibleBooks = [
44
{
55
id: 'GEN',
66
title: 'Genesis',
7-
full_title: 'The First Book of Moses, Called Genesis',
8-
abbreviation: 'Gen',
7+
full_title: 'Genesis',
8+
abbreviation: 'Gen.',
99
canon: 'old_testament',
1010
chapters: mockGenesisChapters,
1111
},

packages/core/src/__tests__/bible.test.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,27 @@ describe('BibleClient', () => {
2727
});
2828

2929
describe('getVersions', () => {
30+
it('should fetch number of Bible versions specified by page_size param', async () => {
31+
const versions = await bibleClient.getVersions('en*', undefined, { page_size: 11 });
32+
33+
expect(versions.data.length).toEqual(11);
34+
});
35+
36+
it('should fetch next page using page_token from first response', async () => {
37+
const firstPage = await bibleClient.getVersions('en*', undefined, { page_size: 5 });
38+
39+
expect(firstPage.data.length).toEqual(5);
40+
expect(firstPage.next_page_token).toBeDefined();
41+
42+
const secondPage = await bibleClient.getVersions('en*', undefined, {
43+
page_size: 5,
44+
page_token: firstPage.next_page_token!,
45+
});
46+
47+
expect(secondPage.data.length).toEqual(5);
48+
expect(secondPage.data[0]?.id).not.toEqual(firstPage.data[0]?.id);
49+
});
50+
3051
it('should fetch Bible versions with language ranges', async () => {
3152
const versions = await bibleClient.getVersions('en*');
3253

@@ -117,16 +138,16 @@ describe('BibleClient', () => {
117138

118139
describe('getBooks', () => {
119140
it('should fetch all books for a version', async () => {
120-
const books = await bibleClient.getBooks(1);
141+
const books = await bibleClient.getBooks(111);
121142

122143
const { success } = BibleBookSchema.safeParse(books.data[0]);
123144
expect(success).toBe(true);
124145

125146
expect(books.data).toHaveLength(66);
126147
expect(books.data[0]).toHaveProperty('id', 'GEN');
127148
expect(books.data[0]).toHaveProperty('title', 'Genesis');
128-
expect(books.data[0]).toHaveProperty('full_title', 'The First Book of Moses, Called Genesis');
129-
expect(books.data[0]).toHaveProperty('abbreviation', 'Gen');
149+
expect(books.data[0]).toHaveProperty('full_title', 'Genesis');
150+
expect(books.data[0]).toHaveProperty('abbreviation', 'Gen.');
130151
expect(books.data[0]?.intro).toEqual({
131152
id: 'INTRO',
132153
passage_id: 'GEN.INTRO',
@@ -139,15 +160,15 @@ describe('BibleClient', () => {
139160

140161
describe('getBook', () => {
141162
it('should fetch a specific book', async () => {
142-
const book = await bibleClient.getBook(1, 'GEN');
163+
const book = await bibleClient.getBook(111, 'GEN');
143164

144165
const { success } = BibleBookSchema.safeParse(book);
145166
expect(success).toBe(true);
146167

147168
expect(book.chapters).toHaveLength(50);
148169
expect(book).toHaveProperty('id', 'GEN');
149170
expect(book).toHaveProperty('title', 'Genesis');
150-
expect(book).toHaveProperty('abbreviation', 'Gen');
171+
expect(book).toHaveProperty('abbreviation', 'Gen.');
151172
expect(book).toHaveProperty('intro');
152173
expect(book.intro).toEqual({
153174
id: 'INTRO',

packages/core/src/__tests__/handlers.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,32 @@ export const handlers = [
106106
}),
107107

108108
// Versions endpoints
109-
http.get(`https://${apiHost}/v1/bibles`, () => {
109+
http.get(`https://${apiHost}/v1/bibles`, ({ request }) => {
110+
const url = new URL(request.url);
111+
const pageSize = url.searchParams.get('page_size');
112+
const pageToken = url.searchParams.get('page_token');
113+
114+
const defaultPageSize = 25;
115+
const size = pageSize ? parseInt(pageSize, 10) : defaultPageSize;
116+
let start = 0;
117+
118+
if (pageToken) {
119+
try {
120+
const decoded = JSON.parse(atob(pageToken)) as { start?: number };
121+
start = decoded.start || 0;
122+
} catch {
123+
start = 0;
124+
}
125+
}
126+
127+
const end = start + size;
128+
const paginatedVersions = mockVersions.slice(start, end);
129+
const hasMore = end < mockVersions.length;
130+
110131
return HttpResponse.json({
111-
data: mockVersions,
112-
next_page_token: null,
113-
total_size: 14,
132+
data: paginatedVersions,
133+
next_page_token: hasMore ? btoa(JSON.stringify({ start: end })) : null,
134+
total_size: mockVersions.length,
114135
});
115136
}),
116137

@@ -127,7 +148,7 @@ export const handlers = [
127148
return HttpResponse.json(mockBibleGenesis);
128149
}),
129150

130-
// Chaper endpoints
151+
// Chapter endpoints
131152
http.get(`https://${apiHost}/v1/bibles/:bible_id/books/:book_id/chapters`, () => {
132153
return HttpResponse.json({ data: mockGenesisChapters });
133154
}),

packages/core/src/__tests__/languages.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ describe('LanguagesClient', () => {
3232
const { success } = LanguageSchema.safeParse(languages.data[0]);
3333
expect(success).toBe(true);
3434
expect(languages.data).toHaveLength(20);
35-
expect(languages.data.every((language) => language.countries?.includes('US'))).toBe(true);
35+
/** This is not true, it will always return the number provided in page_size
36+
* and it will put the ones that have the country in their countries array
37+
* at the top of the list.
38+
*/
39+
// expect(languages.data.every((language) => language.countries?.includes('US'))).toBe(true);
3640
expect(languages.next_page_token).not.toBeNull();
3741
});
3842

packages/core/src/bible.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export class BibleClient {
5757
async getVersions(
5858
language_ranges: string | string[],
5959
license_id?: string | number,
60+
options?: { page_size?: number; page_token?: string },
6061
): Promise<Collection<BibleVersion>> {
6162
const languageRangeArray = Array.isArray(language_ranges) ? language_ranges : [language_ranges];
6263

@@ -68,9 +69,20 @@ export class BibleClient {
6869
const params: Record<string, string | number | string[]> = {
6970
'language_ranges[]': parsedLanguageRanges,
7071
};
72+
7173
if (license_id !== undefined) {
7274
params.license_id = license_id;
7375
}
76+
77+
if (options?.page_size !== undefined) {
78+
const pageSizeSchema = z.number().int().positive();
79+
pageSizeSchema.parse(options.page_size);
80+
params.page_size = options.page_size;
81+
}
82+
83+
if (options?.page_token !== undefined) {
84+
params.page_token = options.page_token;
85+
}
7486
return this.client.get<Collection<BibleVersion>>(`/v1/bibles`, params);
7587
}
7688

0 commit comments

Comments
 (0)