@prezly/theme-kit-nextjs 1.14.0 → 1.15.0-0

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.
Files changed (58) hide show
  1. package/README.md +55 -0
  2. package/build/adapter-nextjs/getNewsroomStaticProps.d.ts +15 -0
  3. package/build/adapter-nextjs/getNewsroomStaticProps.js +69 -0
  4. package/build/adapter-nextjs/getNewsroomStaticProps.js.map +1 -0
  5. package/build/adapter-nextjs/index.d.ts +2 -0
  6. package/build/adapter-nextjs/index.js +2 -0
  7. package/build/adapter-nextjs/index.js.map +1 -1
  8. package/build/adapter-nextjs/page-props/category.d.ts +3 -1
  9. package/build/adapter-nextjs/page-props/category.js +104 -1
  10. package/build/adapter-nextjs/page-props/category.js.map +1 -1
  11. package/build/adapter-nextjs/page-props/gallery.d.ts +2 -1
  12. package/build/adapter-nextjs/page-props/gallery.js +48 -1
  13. package/build/adapter-nextjs/page-props/gallery.js.map +1 -1
  14. package/build/adapter-nextjs/page-props/galleryAlbum.d.ts +3 -1
  15. package/build/adapter-nextjs/page-props/galleryAlbum.js +61 -1
  16. package/build/adapter-nextjs/page-props/galleryAlbum.js.map +1 -1
  17. package/build/adapter-nextjs/page-props/home.d.ts +2 -1
  18. package/build/adapter-nextjs/page-props/home.js +48 -1
  19. package/build/adapter-nextjs/page-props/home.js.map +1 -1
  20. package/build/adapter-nextjs/page-props/index.d.ts +6 -6
  21. package/build/adapter-nextjs/page-props/index.js +10 -1
  22. package/build/adapter-nextjs/page-props/index.js.map +1 -1
  23. package/build/adapter-nextjs/page-props/lib/types.d.ts +2 -2
  24. package/build/adapter-nextjs/page-props/search.d.ts +1 -0
  25. package/build/adapter-nextjs/page-props/search.js +30 -1
  26. package/build/adapter-nextjs/page-props/search.js.map +1 -1
  27. package/build/adapter-nextjs/page-props/story.d.ts +10 -1
  28. package/build/adapter-nextjs/page-props/story.js +69 -1
  29. package/build/adapter-nextjs/page-props/story.js.map +1 -1
  30. package/build/adapter-nextjs/processStaticRequest.d.ts +11 -0
  31. package/build/adapter-nextjs/processStaticRequest.js +37 -0
  32. package/build/adapter-nextjs/processStaticRequest.js.map +1 -0
  33. package/build/data-fetching/api/PrezlyApi.d.ts +3 -2
  34. package/build/data-fetching/api/PrezlyApi.js +22 -4
  35. package/build/data-fetching/api/PrezlyApi.js.map +1 -1
  36. package/build/intl/languages.js +3 -1
  37. package/build/intl/languages.js.map +1 -1
  38. package/build/intl/localeConfig.js +5 -1
  39. package/build/intl/localeConfig.js.map +1 -1
  40. package/build/tsconfig.tsbuildinfo +1 -1
  41. package/package.json +5 -5
  42. package/src/__mocks__/languages.ts +43 -0
  43. package/src/adapter-nextjs/getNewsroomStaticProps.ts +29 -0
  44. package/src/adapter-nextjs/index.ts +2 -0
  45. package/src/adapter-nextjs/page-props/category.ts +85 -2
  46. package/src/adapter-nextjs/page-props/gallery.ts +48 -1
  47. package/src/adapter-nextjs/page-props/galleryAlbum.ts +47 -1
  48. package/src/adapter-nextjs/page-props/home.ts +46 -1
  49. package/src/adapter-nextjs/page-props/index.ts +24 -6
  50. package/src/adapter-nextjs/page-props/lib/types.ts +2 -2
  51. package/src/adapter-nextjs/page-props/search.ts +19 -0
  52. package/src/adapter-nextjs/page-props/story.ts +49 -1
  53. package/src/adapter-nextjs/processStaticRequest.ts +32 -0
  54. package/src/data-fetching/api/PrezlyApi.ts +19 -5
  55. package/src/intl/languages.test.ts +12 -1
  56. package/src/intl/languages.ts +3 -1
  57. package/src/intl/localeConfig.js +5 -1
  58. package/src/intl/localeObject.test.ts +3 -0
@@ -1,10 +1,20 @@
1
1
  import type { ExtraStoryFields, Story } from '@prezly/sdk';
2
- import type { GetServerSidePropsContext, GetServerSidePropsResult } from 'next';
2
+ import type {
3
+ GetServerSidePropsContext,
4
+ GetServerSidePropsResult,
5
+ GetStaticPathsResult,
6
+ GetStaticPropsContext,
7
+ GetStaticPropsResult,
8
+ } from 'next';
3
9
 
10
+ import { getPrezlyApi } from '../../data-fetching';
4
11
  import type { PaginationProps } from '../../infinite-loading/types';
5
- import { DEFAULT_PAGE_SIZE } from '../../utils';
12
+ import { LocaleObject } from '../../intl';
13
+ import { DEFAULT_PAGE_SIZE, getLocalizedCategoryData } from '../../utils';
6
14
  import { getNewsroomServerSideProps } from '../getNewsroomServerSideProps';
15
+ import { getNewsroomStaticProps } from '../getNewsroomStaticProps';
7
16
  import { processRequest } from '../processRequest';
17
+ import { processStaticRequest } from '../processStaticRequest';
8
18
 
9
19
  import type { PropsFunction } from './lib/types';
10
20
 
@@ -73,3 +83,76 @@ export function getCategoryPageServerSideProps<
73
83
  );
74
84
  };
75
85
  }
86
+
87
+ export function getCategoryPageStaticProps<
88
+ CustomProps extends Record<string, any>,
89
+ StoryType extends Story = Story,
90
+ >(customProps: CustomProps | PropsFunction<CustomProps>, options?: Options) {
91
+ const { pageSize = DEFAULT_PAGE_SIZE, extraStoryFields } = options || {};
92
+
93
+ return async function getStaticProps(
94
+ context: GetStaticPropsContext,
95
+ ): Promise<GetStaticPropsResult<CategoryPageProps<StoryType> & CustomProps>> {
96
+ const { api, staticProps } = await getNewsroomStaticProps(context);
97
+
98
+ const { slug } = context.params as { slug: string };
99
+ const category = await api.getCategoryBySlug(slug);
100
+
101
+ if (!category) {
102
+ return {
103
+ notFound: true,
104
+ };
105
+ }
106
+
107
+ const { localeCode } = staticProps.newsroomContextProps;
108
+
109
+ const { stories, storiesTotal } = await api.getStoriesFromCategory(category, {
110
+ pageSize,
111
+ include: extraStoryFields,
112
+ localeCode,
113
+ });
114
+
115
+ return processStaticRequest(context, {
116
+ ...staticProps,
117
+ newsroomContextProps: {
118
+ ...staticProps.newsroomContextProps,
119
+ currentCategory: category,
120
+ },
121
+ // TODO: This is temporary until return types from API are figured out
122
+ stories: stories as StoryType[],
123
+ pagination: {
124
+ itemsTotal: storiesTotal,
125
+ currentPage: 1,
126
+ pageSize,
127
+ },
128
+ ...(typeof customProps === 'function'
129
+ ? await (customProps as PropsFunction<CustomProps>)(context, staticProps)
130
+ : customProps),
131
+ });
132
+ };
133
+ }
134
+
135
+ export async function getCategoryPageStaticPaths(): Promise<GetStaticPathsResult> {
136
+ const api = getPrezlyApi();
137
+ const [categories, defaultLanguage] = await Promise.all([
138
+ api.getCategories(),
139
+ api.getNewsroomDefaultLanguage(),
140
+ ]);
141
+ const locale = LocaleObject.fromAnyCode(defaultLanguage.code);
142
+
143
+ const paths = categories
144
+ .map((category) => {
145
+ const { slug } = getLocalizedCategoryData(category, locale);
146
+ if (!slug) {
147
+ return undefined;
148
+ }
149
+
150
+ return { params: { slug } };
151
+ })
152
+ .filter<{ params: { slug: string } }>(Boolean as any);
153
+
154
+ return {
155
+ paths,
156
+ fallback: 'blocking',
157
+ };
158
+ }
@@ -1,10 +1,17 @@
1
1
  import type { NewsroomGallery } from '@prezly/sdk';
2
- import type { GetServerSidePropsContext, GetServerSidePropsResult } from 'next';
2
+ import type {
3
+ GetServerSidePropsContext,
4
+ GetServerSidePropsResult,
5
+ GetStaticPropsContext,
6
+ GetStaticPropsResult,
7
+ } from 'next';
3
8
 
4
9
  import type { PaginationProps } from '../../infinite-loading/types';
5
10
  import { DEFAULT_GALLERY_PAGE_SIZE } from '../../utils';
6
11
  import { getNewsroomServerSideProps } from '../getNewsroomServerSideProps';
12
+ import { getNewsroomStaticProps } from '../getNewsroomStaticProps';
7
13
  import { processRequest } from '../processRequest';
14
+ import { processStaticRequest } from '../processStaticRequest';
8
15
 
9
16
  import type { PropsFunction } from './lib/types';
10
17
 
@@ -62,3 +69,43 @@ export function getGalleryPageServerSideProps<CustomProps extends Record<string,
62
69
  );
63
70
  };
64
71
  }
72
+
73
+ export function getGalleryPageStaticProps<CustomProps extends Record<string, any>>(
74
+ customProps: CustomProps | PropsFunction<CustomProps>,
75
+ options?: Options,
76
+ ) {
77
+ const { pageSize = DEFAULT_GALLERY_PAGE_SIZE } = options || {};
78
+
79
+ return async function getStaticProps(
80
+ context: GetStaticPropsContext,
81
+ ): Promise<GetStaticPropsResult<GalleryPageProps & CustomProps>> {
82
+ const { api, staticProps } = await getNewsroomStaticProps(context);
83
+
84
+ const { galleries, pagination } = await api.getGalleries({ pageSize });
85
+
86
+ // If there's only one gallery, redirect to it immediately
87
+ if (galleries.length === 1) {
88
+ const { uuid } = galleries[0];
89
+
90
+ return {
91
+ redirect: {
92
+ destination: `/media/album/${uuid}`,
93
+ permanent: false,
94
+ },
95
+ };
96
+ }
97
+
98
+ return processStaticRequest(context, {
99
+ ...staticProps,
100
+ galleries,
101
+ pagination: {
102
+ itemsTotal: pagination.matched_records_number,
103
+ currentPage: 1,
104
+ pageSize,
105
+ },
106
+ ...(typeof customProps === 'function'
107
+ ? await (customProps as PropsFunction<CustomProps>)(context, staticProps)
108
+ : customProps),
109
+ });
110
+ };
111
+ }
@@ -1,8 +1,17 @@
1
1
  import type { NewsroomGallery } from '@prezly/sdk';
2
- import type { GetServerSidePropsContext, GetServerSidePropsResult } from 'next';
2
+ import type {
3
+ GetServerSidePropsContext,
4
+ GetServerSidePropsResult,
5
+ GetStaticPathsResult,
6
+ GetStaticPropsContext,
7
+ GetStaticPropsResult,
8
+ } from 'next';
3
9
 
10
+ import { getPrezlyApi } from '../../data-fetching';
4
11
  import { getNewsroomServerSideProps } from '../getNewsroomServerSideProps';
12
+ import { getNewsroomStaticProps } from '../getNewsroomStaticProps';
5
13
  import { processRequest } from '../processRequest';
14
+ import { processStaticRequest } from '../processStaticRequest';
6
15
 
7
16
  import type { PropsFunction } from './lib/types';
8
17
 
@@ -38,3 +47,40 @@ export function getGalleryAlbumPageServerSideProps<CustomProps extends Record<st
38
47
  );
39
48
  };
40
49
  }
50
+
51
+ export function getGalleryAlbumPageStaticProps<CustomProps extends Record<string, any>>(
52
+ customProps: CustomProps | PropsFunction<CustomProps>,
53
+ ) {
54
+ return async function getStaticProps(
55
+ context: GetStaticPropsContext,
56
+ ): Promise<GetStaticPropsResult<GalleryAlbumPageProps & CustomProps>> {
57
+ const { api, staticProps } = await getNewsroomStaticProps(context);
58
+
59
+ const { uuid } = context.params as { uuid: string };
60
+ const gallery = await api.getGallery(uuid);
61
+
62
+ if (!gallery || !gallery.images_number) {
63
+ return { notFound: true };
64
+ }
65
+
66
+ return processStaticRequest(context, {
67
+ ...staticProps,
68
+ gallery,
69
+ ...(typeof customProps === 'function'
70
+ ? await (customProps as PropsFunction<CustomProps>)(context, staticProps)
71
+ : customProps),
72
+ });
73
+ };
74
+ }
75
+
76
+ export async function getGalleryAlbumPageStaticPaths(): Promise<GetStaticPathsResult> {
77
+ const api = getPrezlyApi();
78
+ const { galleries } = await api.getGalleries({});
79
+
80
+ const paths = galleries.map(({ uuid }) => ({ params: { uuid } }));
81
+
82
+ return {
83
+ paths,
84
+ fallback: 'blocking',
85
+ };
86
+ }
@@ -1,10 +1,17 @@
1
1
  import type { ExtraStoryFields, Story } from '@prezly/sdk';
2
- import type { GetServerSidePropsContext, GetServerSidePropsResult } from 'next';
2
+ import type {
3
+ GetServerSidePropsContext,
4
+ GetServerSidePropsResult,
5
+ GetStaticPropsContext,
6
+ GetStaticPropsResult,
7
+ } from 'next';
3
8
 
4
9
  import type { PaginationProps } from '../../infinite-loading/types';
5
10
  import { DEFAULT_PAGE_SIZE } from '../../utils';
6
11
  import { getNewsroomServerSideProps } from '../getNewsroomServerSideProps';
12
+ import { getNewsroomStaticProps } from '../getNewsroomStaticProps';
7
13
  import { processRequest } from '../processRequest';
14
+ import { processStaticRequest } from '../processStaticRequest';
8
15
 
9
16
  import type { PropsFunction } from './lib/types';
10
17
 
@@ -63,3 +70,41 @@ export function getHomepageServerSideProps<
63
70
  );
64
71
  };
65
72
  }
73
+
74
+ export function getHomepageStaticProps<
75
+ CustomProps extends Record<string, any>,
76
+ StoryType extends Story = Story,
77
+ >(customProps: CustomProps | PropsFunction<CustomProps>, options?: Options) {
78
+ const { pageSize = DEFAULT_PAGE_SIZE, extraStoryFields } = options || {};
79
+
80
+ return async function getStaticProps(
81
+ context: GetStaticPropsContext,
82
+ ): Promise<GetStaticPropsResult<HomePageProps<StoryType> & CustomProps>> {
83
+ const { api, staticProps } = await getNewsroomStaticProps(context, {
84
+ loadHomepageContacts: true,
85
+ });
86
+
87
+ const { localeCode } = staticProps.newsroomContextProps;
88
+
89
+ const storiesPaginated = await api.getStories({
90
+ pageSize,
91
+ include: extraStoryFields,
92
+ localeCode,
93
+ });
94
+ const { stories, storiesTotal } = storiesPaginated;
95
+
96
+ return processStaticRequest(context, {
97
+ ...staticProps,
98
+ // TODO: This is temporary until return types from API are figured out
99
+ stories: stories as StoryType[],
100
+ pagination: {
101
+ itemsTotal: storiesTotal,
102
+ currentPage: 1,
103
+ pageSize,
104
+ },
105
+ ...(typeof customProps === 'function'
106
+ ? await (customProps as PropsFunction<CustomProps>)(context, staticProps)
107
+ : customProps),
108
+ });
109
+ };
110
+ }
@@ -1,8 +1,26 @@
1
- export { getCategoryPageServerSideProps, type CategoryPageProps } from './category';
2
- export { getGalleryPageServerSideProps, type GalleryPageProps } from './gallery';
3
- export { getGalleryAlbumPageServerSideProps, type GalleryAlbumPageProps } from './galleryAlbum';
4
- export { getHomepageServerSideProps, type HomePageProps } from './home';
5
- export { getSearchPageServerSideProps } from './search';
1
+ export {
2
+ getCategoryPageServerSideProps,
3
+ getCategoryPageStaticPaths,
4
+ getCategoryPageStaticProps,
5
+ type CategoryPageProps,
6
+ } from './category';
7
+ export {
8
+ getGalleryPageServerSideProps,
9
+ getGalleryPageStaticProps,
10
+ type GalleryPageProps,
11
+ } from './gallery';
12
+ export {
13
+ getGalleryAlbumPageServerSideProps,
14
+ getGalleryAlbumPageStaticPaths,
15
+ getGalleryAlbumPageStaticProps,
16
+ type GalleryAlbumPageProps,
17
+ } from './galleryAlbum';
18
+ export { getHomepageServerSideProps, getHomepageStaticProps, type HomePageProps } from './home';
19
+ export { getSearchPageServerSideProps, getSearchPageStaticProps } from './search';
6
20
  export * from './sitemap';
7
- export { getStoryPageServerSideProps } from './story';
21
+ export {
22
+ getStoryPageServerSideProps,
23
+ getStoryPageStaticPaths,
24
+ getStoryPageStaticProps,
25
+ } from './story';
8
26
  export { getStoryPreviewPageServerSideProps } from './storyPreview';
@@ -1,8 +1,8 @@
1
- import type { GetServerSidePropsContext } from 'next';
1
+ import type { GetServerSidePropsContext, GetStaticPropsContext } from 'next';
2
2
 
3
3
  import type { PageProps } from '../../../types';
4
4
 
5
5
  export type PropsFunction<CustomProps> = (
6
- context: GetServerSidePropsContext,
6
+ context: GetServerSidePropsContext | GetStaticPropsContext,
7
7
  props: PageProps,
8
8
  ) => CustomProps | Promise<CustomProps>;
@@ -1,7 +1,9 @@
1
1
  import type { GetServerSidePropsContext, GetServerSidePropsResult } from 'next';
2
2
 
3
3
  import { getNewsroomServerSideProps } from '../getNewsroomServerSideProps';
4
+ import { getNewsroomStaticProps } from '../getNewsroomStaticProps';
4
5
  import { processRequest } from '../processRequest';
6
+ import { processStaticRequest } from '../processStaticRequest';
5
7
 
6
8
  import type { PropsFunction } from './lib/types';
7
9
 
@@ -25,3 +27,20 @@ export function getSearchPageServerSideProps<CustomProps extends Record<string,
25
27
  );
26
28
  };
27
29
  }
30
+
31
+ export function getSearchPageStaticProps<CustomProps extends Record<string, any>>(
32
+ customProps: CustomProps | PropsFunction<CustomProps>,
33
+ ) {
34
+ return async function getStaticProps(
35
+ context: GetServerSidePropsContext,
36
+ ): Promise<GetServerSidePropsResult<CustomProps>> {
37
+ const { staticProps } = await getNewsroomStaticProps(context);
38
+
39
+ return processStaticRequest(context, {
40
+ ...staticProps,
41
+ ...(typeof customProps === 'function'
42
+ ? await (customProps as PropsFunction<CustomProps>)(context, staticProps)
43
+ : customProps),
44
+ });
45
+ };
46
+ }
@@ -1,9 +1,16 @@
1
- import type { GetServerSidePropsContext, GetServerSidePropsResult } from 'next';
1
+ import type {
2
+ GetServerSidePropsContext,
3
+ GetServerSidePropsResult,
4
+ GetStaticPropsContext,
5
+ GetStaticPropsResult,
6
+ } from 'next';
2
7
 
3
8
  import { getPrezlyApi } from '../../data-fetching';
4
9
  import { DUMMY_DEFAULT_LOCALE } from '../../intl';
5
10
  import { getNewsroomServerSideProps } from '../getNewsroomServerSideProps';
11
+ import { getNewsroomStaticProps } from '../getNewsroomStaticProps';
6
12
  import { processRequest } from '../processRequest';
13
+ import { processStaticRequest } from '../processStaticRequest';
7
14
 
8
15
  import type { PropsFunction } from './lib/types';
9
16
 
@@ -45,3 +52,44 @@ export function getStoryPageServerSideProps<CustomProps extends Record<string, a
45
52
  });
46
53
  };
47
54
  }
55
+
56
+ export function getStoryPageStaticProps<CustomProps extends Record<string, any>>(
57
+ customProps: CustomProps | PropsFunction<CustomProps>,
58
+ ) {
59
+ return async function getStaticProps(
60
+ context: GetStaticPropsContext,
61
+ ): Promise<GetStaticPropsResult<CustomProps>> {
62
+ const api = getPrezlyApi();
63
+
64
+ const { slug } = context.params as { slug?: string };
65
+ const story = slug ? await api.getStoryBySlug(slug) : null;
66
+ if (!story) {
67
+ return { notFound: true };
68
+ }
69
+
70
+ const { staticProps } = await getNewsroomStaticProps(context, { story });
71
+
72
+ return processStaticRequest(context, {
73
+ ...staticProps,
74
+ newsroomContextProps: {
75
+ ...staticProps.newsroomContextProps,
76
+ currentStory: story,
77
+ },
78
+ ...(typeof customProps === 'function'
79
+ ? await (customProps as PropsFunction<CustomProps>)(context, staticProps)
80
+ : customProps),
81
+ });
82
+ };
83
+ }
84
+
85
+ export async function getStoryPageStaticPaths() {
86
+ const api = getPrezlyApi();
87
+ const stories = await api.getAllStories();
88
+
89
+ const paths = stories.map(({ slug }) => ({ params: { slug } }));
90
+
91
+ return {
92
+ paths,
93
+ fallback: 'blocking',
94
+ };
95
+ }
@@ -0,0 +1,32 @@
1
+ import type { GetStaticPropsContext, GetStaticPropsResult } from 'next';
2
+
3
+ import type { PageProps, ServerSidePageProps } from '../types';
4
+
5
+ /**
6
+ * This function combines the props returned from `getNewsroomStaticProps` and your optional custom props for the page.
7
+ * See README for usage examples.
8
+ *
9
+ * @param context Next.js context passed to the `getStaticProps` method of the page
10
+ * @param props Object containing the return of `getNewsroomServerSideProps` and your optional custom props.
11
+ * @param revalidateTimeout Optional: timeout in seconds to use with Next ISR.
12
+ */
13
+ export function processStaticRequest<Props>(
14
+ context: GetStaticPropsContext,
15
+ props: Props & PageProps & ServerSidePageProps,
16
+ revalidateTimeout?: number,
17
+ ): GetStaticPropsResult<Props> {
18
+ const { locale: nextLocale } = context;
19
+
20
+ const { localeResolved, ...pageProps } = props;
21
+
22
+ // If no locale was provided by Next, it most likely means that the theme is not supporting multi-language.
23
+ // In that case we won't show 404 page.
24
+ if (!localeResolved && nextLocale) {
25
+ return { notFound: true };
26
+ }
27
+
28
+ return {
29
+ props: pageProps as Props & PageProps,
30
+ revalidate: revalidateTimeout,
31
+ };
32
+ }
@@ -30,6 +30,9 @@ import {
30
30
  const CATEGORIES_SORT_ORDER = '+order';
31
31
  const DEFAULT_SORT_ORDER: SortOrder = 'desc';
32
32
 
33
+ const ERROR_CODE_NOT_FOUND = 404;
34
+ const ERROR_CODE_GONE = 410;
35
+
33
36
  type SortOrder = 'desc' | 'asc';
34
37
 
35
38
  interface GetStoriesOptions {
@@ -42,7 +45,7 @@ interface GetStoriesOptions {
42
45
 
43
46
  interface GetGalleriesOptions {
44
47
  page?: number;
45
- pageSize: number;
48
+ pageSize?: number;
46
49
  }
47
50
 
48
51
  export class PrezlyApi {
@@ -72,7 +75,10 @@ export class PrezlyApi {
72
75
  try {
73
76
  return await this.sdk.stories.get(uuid);
74
77
  } catch (error) {
75
- if (isSdkError(error) && error.status === 404) {
78
+ if (
79
+ isSdkError(error) &&
80
+ (error.status === ERROR_CODE_NOT_FOUND || error.status === ERROR_CODE_GONE)
81
+ ) {
76
82
  return null;
77
83
  }
78
84
  throw error;
@@ -204,10 +210,13 @@ export class PrezlyApi {
204
210
  searchStories: typeof PrezlySDK.prototype.stories.search = (options) =>
205
211
  this.sdk.stories.search(options);
206
212
 
207
- async getGalleries({ page = undefined, pageSize }: GetGalleriesOptions) {
213
+ async getGalleries({ page, pageSize }: GetGalleriesOptions) {
208
214
  return this.sdk.newsroomGalleries.list(this.newsroomUuid, {
209
215
  limit: pageSize,
210
- offset: typeof page === 'undefined' ? undefined : (page - 1) * pageSize,
216
+ offset:
217
+ typeof page === 'undefined' || typeof pageSize === 'undefined'
218
+ ? undefined
219
+ : (page - 1) * pageSize,
211
220
  scope: getGalleriesQuery(),
212
221
  });
213
222
  }
@@ -242,7 +251,7 @@ export class PrezlyApi {
242
251
  }
243
252
 
244
253
  async getNewsroomServerSideProps(
245
- request: IncomingMessage | undefined,
254
+ request?: IncomingMessage,
246
255
  nextLocaleIsoCode?: string,
247
256
  story?: Story,
248
257
  ): Promise<PageProps & ServerSidePageProps> {
@@ -279,4 +288,9 @@ export class PrezlyApi {
279
288
  localeResolved: Boolean(currentLanguage),
280
289
  };
281
290
  }
291
+
292
+ async getNewsroomDefaultLanguage() {
293
+ const languages = await this.getNewsroomLanguages();
294
+ return getDefaultLanguage(languages);
295
+ }
282
296
  }
@@ -200,7 +200,12 @@ describe('getShortestLocaleCode', () => {
200
200
  });
201
201
 
202
202
  it('returns neutral language code if it is the only culture with that language', () => {
203
- expect(getShortestLocaleCode(ALL_LANGUAGES, LocaleObject.fromAnyCode('es-ES'))).toBe('es');
203
+ expect(
204
+ getShortestLocaleCode(
205
+ ALL_LANGUAGES.filter(({ code }) => code !== 'es_419'),
206
+ LocaleObject.fromAnyCode('es-ES'),
207
+ ),
208
+ ).toBe('es');
204
209
  });
205
210
 
206
211
  it('returns region code if it is the only culture with that region', () => {
@@ -218,4 +223,10 @@ describe('getShortestLocaleCode', () => {
218
223
  'nl_BE',
219
224
  );
220
225
  });
226
+
227
+ it('returns full code when trying to shorten to region code for es-419', () => {
228
+ expect(getShortestLocaleCode(ALL_LANGUAGES, LocaleObject.fromAnyCode('es-419'))).toBe(
229
+ 'es_419',
230
+ );
231
+ });
221
232
  });
@@ -212,7 +212,9 @@ export function getShortestLocaleCode(
212
212
  if (
213
213
  matchingLanguagesByRegionCode.length === 1 &&
214
214
  // If there are 2 or more matching neutral languages, it means that there are no languages that can be shortened to neutral code
215
- mathchingNeutralLanguagesByRegionCode.length !== 1
215
+ mathchingNeutralLanguagesByRegionCode.length !== 1 &&
216
+ // We don't want just numbers in our region code
217
+ Number.isNaN(Number(shortRegionCode))
216
218
  ) {
217
219
  return shortRegionCode;
218
220
  }
@@ -12,7 +12,11 @@ const lowercaseLocalPermutations = Array.from(
12
12
  new Set([
13
13
  ...lowercaseLocales,
14
14
  ...lowercaseLocales.map((code) => code.split('-')[0]),
15
- ...lowercaseLocales.map((code) => code.split('-')[1]).filter(Boolean),
15
+ ...lowercaseLocales
16
+ .map((code) => code.split('-')[1])
17
+ .filter(Boolean)
18
+ // Remove number-only codes from possible permutations (like `419` for `es-419`)
19
+ .filter((code) => Number.isNaN(Number(code))),
16
20
  ]),
17
21
  ).sort();
18
22
 
@@ -24,6 +24,9 @@ it('accepts any valid code type and converts it to hyphen code consistently', ()
24
24
  expect(LocaleObject.fromAnyCode('en_us').toHyphenCode()).toBe('en-US');
25
25
  expect(LocaleObject.fromAnyCode('en_US').toHyphenCode()).toBe('en-US');
26
26
  expect(LocaleObject.fromAnyCode('EN_US').toHyphenCode()).toBe('en-US');
27
+
28
+ expect(LocaleObject.fromAnyCode('es-419').toHyphenCode()).toBe('es-419');
29
+ expect(LocaleObject.fromAnyCode('es_419').toHyphenCode()).toBe('es-419');
27
30
  });
28
31
 
29
32
  it('converts to underscore code consistently', () => {