@prezly/theme-kit-nextjs 1.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.
- package/LICENSE +21 -0
- package/README.md +28 -0
- package/build/adapter-nextjs/getBasePageProps.d.ts +9 -0
- package/build/adapter-nextjs/getBasePageProps.js +11 -0
- package/build/adapter-nextjs/getBasePageProps.js.map +1 -0
- package/build/adapter-nextjs/index.d.ts +2 -0
- package/build/adapter-nextjs/index.js +3 -0
- package/build/adapter-nextjs/index.js.map +1 -0
- package/build/adapter-nextjs/processRequest.d.ts +3 -0
- package/build/adapter-nextjs/processRequest.js +20 -0
- package/build/adapter-nextjs/processRequest.js.map +1 -0
- package/build/data-fetching/api/PrezlyApi.d.ts +43 -0
- package/build/data-fetching/api/PrezlyApi.js +139 -0
- package/build/data-fetching/api/PrezlyApi.js.map +1 -0
- package/build/data-fetching/api/getPrezlyApi.d.ts +4 -0
- package/build/data-fetching/api/getPrezlyApi.js +17 -0
- package/build/data-fetching/api/getPrezlyApi.js.map +1 -0
- package/build/data-fetching/api/index.d.ts +2 -0
- package/build/data-fetching/api/index.js +3 -0
- package/build/data-fetching/api/index.js.map +1 -0
- package/build/data-fetching/api/languages.d.ts +18 -0
- package/build/data-fetching/api/languages.js +117 -0
- package/build/data-fetching/api/languages.js.map +1 -0
- package/build/data-fetching/api/queries.d.ts +45 -0
- package/build/data-fetching/api/queries.js +35 -0
- package/build/data-fetching/api/queries.js.map +1 -0
- package/build/data-fetching/constants.d.ts +2 -0
- package/build/data-fetching/constants.js +3 -0
- package/build/data-fetching/constants.js.map +1 -0
- package/build/data-fetching/getAssetsUrl.d.ts +1 -0
- package/build/data-fetching/getAssetsUrl.js +5 -0
- package/build/data-fetching/getAssetsUrl.js.map +1 -0
- package/build/data-fetching/getLocalizedCategoryData.d.ts +10 -0
- package/build/data-fetching/getLocalizedCategoryData.js +31 -0
- package/build/data-fetching/getLocalizedCategoryData.js.map +1 -0
- package/build/data-fetching/getNewsroomLogoUrl.d.ts +3 -0
- package/build/data-fetching/getNewsroomLogoUrl.js +14 -0
- package/build/data-fetching/getNewsroomLogoUrl.js.map +1 -0
- package/build/data-fetching/getPrivacyPortalUrl.d.ts +8 -0
- package/build/data-fetching/getPrivacyPortalUrl.js +9 -0
- package/build/data-fetching/getPrivacyPortalUrl.js.map +1 -0
- package/build/data-fetching/getStoryPublicationDate.d.ts +3 -0
- package/build/data-fetching/getStoryPublicationDate.jsx +10 -0
- package/build/data-fetching/getStoryPublicationDate.jsx.map +1 -0
- package/build/data-fetching/getUploadcareGroupUrl.d.ts +1 -0
- package/build/data-fetching/getUploadcareGroupUrl.js +5 -0
- package/build/data-fetching/getUploadcareGroupUrl.js.map +1 -0
- package/build/data-fetching/index.d.ts +9 -0
- package/build/data-fetching/index.js +10 -0
- package/build/data-fetching/index.js.map +1 -0
- package/build/data-fetching/lib/getAlgoliaSettings.d.ts +4 -0
- package/build/data-fetching/lib/getAlgoliaSettings.js +18 -0
- package/build/data-fetching/lib/getAlgoliaSettings.js.map +1 -0
- package/build/data-fetching/lib/getEnvVariables.d.ts +4 -0
- package/build/data-fetching/lib/getEnvVariables.js +37 -0
- package/build/data-fetching/lib/getEnvVariables.js.map +1 -0
- package/build/data-fetching/types.d.ts +11 -0
- package/build/data-fetching/types.js +2 -0
- package/build/data-fetching/types.js.map +1 -0
- package/build/index.d.ts +5 -0
- package/build/index.js +6 -0
- package/build/index.js.map +1 -0
- package/build/intl/index.d.ts +4 -0
- package/build/intl/index.js +5 -0
- package/build/intl/index.js.map +1 -0
- package/build/intl/lang.d.ts +12 -0
- package/build/intl/lang.js +25 -0
- package/build/intl/lang.js.map +1 -0
- package/build/intl/locale.d.ts +10 -0
- package/build/intl/locale.js +93 -0
- package/build/intl/locale.js.map +1 -0
- package/build/intl/localeConfig.d.ts +2 -0
- package/build/intl/localeConfig.js +113 -0
- package/build/intl/localeConfig.js.map +1 -0
- package/build/intl/localeObject.d.ts +22 -0
- package/build/intl/localeObject.js +59 -0
- package/build/intl/localeObject.js.map +1 -0
- package/build/newsroom-context/context.d.ts +26 -0
- package/build/newsroom-context/context.jsx +22 -0
- package/build/newsroom-context/context.jsx.map +1 -0
- package/build/newsroom-context/hooks/index.d.ts +11 -0
- package/build/newsroom-context/hooks/index.js +12 -0
- package/build/newsroom-context/hooks/index.js.map +1 -0
- package/build/newsroom-context/hooks/useAlgoliaSettings.d.ts +1 -0
- package/build/newsroom-context/hooks/useAlgoliaSettings.js +6 -0
- package/build/newsroom-context/hooks/useAlgoliaSettings.js.map +1 -0
- package/build/newsroom-context/hooks/useCategories.d.ts +1 -0
- package/build/newsroom-context/hooks/useCategories.js +6 -0
- package/build/newsroom-context/hooks/useCategories.js.map +1 -0
- package/build/newsroom-context/hooks/useCompanyInformation.d.ts +1 -0
- package/build/newsroom-context/hooks/useCompanyInformation.js +6 -0
- package/build/newsroom-context/hooks/useCompanyInformation.js.map +1 -0
- package/build/newsroom-context/hooks/useCurrentLocale.d.ts +1 -0
- package/build/newsroom-context/hooks/useCurrentLocale.js +6 -0
- package/build/newsroom-context/hooks/useCurrentLocale.js.map +1 -0
- package/build/newsroom-context/hooks/useGetLinkLocaleSlug.d.ts +2 -0
- package/build/newsroom-context/hooks/useGetLinkLocaleSlug.js +21 -0
- package/build/newsroom-context/hooks/useGetLinkLocaleSlug.js.map +1 -0
- package/build/newsroom-context/hooks/useGetTranslationUrl.d.ts +2 -0
- package/build/newsroom-context/hooks/useGetTranslationUrl.js +36 -0
- package/build/newsroom-context/hooks/useGetTranslationUrl.js.map +1 -0
- package/build/newsroom-context/hooks/useLanguages.d.ts +1 -0
- package/build/newsroom-context/hooks/useLanguages.js +6 -0
- package/build/newsroom-context/hooks/useLanguages.js.map +1 -0
- package/build/newsroom-context/hooks/useNewsroom.d.ts +1 -0
- package/build/newsroom-context/hooks/useNewsroom.js +6 -0
- package/build/newsroom-context/hooks/useNewsroom.js.map +1 -0
- package/build/newsroom-context/hooks/useNewsroomContext.d.ts +2 -0
- package/build/newsroom-context/hooks/useNewsroomContext.js +12 -0
- package/build/newsroom-context/hooks/useNewsroomContext.js.map +1 -0
- package/build/newsroom-context/hooks/useSelectedCategory.d.ts +1 -0
- package/build/newsroom-context/hooks/useSelectedCategory.js +6 -0
- package/build/newsroom-context/hooks/useSelectedCategory.js.map +1 -0
- package/build/newsroom-context/hooks/useSelectedStory.d.ts +1 -0
- package/build/newsroom-context/hooks/useSelectedStory.js +6 -0
- package/build/newsroom-context/hooks/useSelectedStory.js.map +1 -0
- package/build/newsroom-context/index.d.ts +2 -0
- package/build/newsroom-context/index.js +3 -0
- package/build/newsroom-context/index.js.map +1 -0
- package/build/types.d.ts +38 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +60 -0
- package/src/@types/global.d.ts +7 -0
- package/src/adapter-nextjs/getBasePageProps.ts +23 -0
- package/src/adapter-nextjs/index.ts +2 -0
- package/src/adapter-nextjs/processRequest.ts +31 -0
- package/src/data-fetching/api/PrezlyApi.ts +240 -0
- package/src/data-fetching/api/getPrezlyApi.ts +24 -0
- package/src/data-fetching/api/index.ts +2 -0
- package/src/data-fetching/api/languages.ts +172 -0
- package/src/data-fetching/api/queries.ts +44 -0
- package/src/data-fetching/constants.ts +2 -0
- package/src/data-fetching/getAssetsUrl.ts +5 -0
- package/src/data-fetching/getLocalizedCategoryData.ts +47 -0
- package/src/data-fetching/getNewsroomLogoUrl.ts +21 -0
- package/src/data-fetching/getPrivacyPortalUrl.ts +22 -0
- package/src/data-fetching/getStoryPublicationDate.tsx +15 -0
- package/src/data-fetching/getUploadcareGroupUrl.ts +5 -0
- package/src/data-fetching/index.ts +9 -0
- package/src/data-fetching/lib/getAlgoliaSettings.ts +29 -0
- package/src/data-fetching/lib/getEnvVariables.ts +44 -0
- package/src/data-fetching/types.ts +12 -0
- package/src/index.ts +5 -0
- package/src/intl/index.ts +4 -0
- package/src/intl/lang.ts +36 -0
- package/src/intl/locale.ts +118 -0
- package/src/intl/localeConfig.js +116 -0
- package/src/intl/localeObject.ts +73 -0
- package/src/newsroom-context/context.tsx +73 -0
- package/src/newsroom-context/hooks/index.ts +11 -0
- package/src/newsroom-context/hooks/useAlgoliaSettings.ts +7 -0
- package/src/newsroom-context/hooks/useCategories.ts +7 -0
- package/src/newsroom-context/hooks/useCompanyInformation.ts +7 -0
- package/src/newsroom-context/hooks/useCurrentLocale.ts +7 -0
- package/src/newsroom-context/hooks/useGetLinkLocaleSlug.ts +33 -0
- package/src/newsroom-context/hooks/useGetTranslationUrl.ts +61 -0
- package/src/newsroom-context/hooks/useLanguages.ts +7 -0
- package/src/newsroom-context/hooks/useNewsroom.ts +7 -0
- package/src/newsroom-context/hooks/useNewsroomContext.ts +14 -0
- package/src/newsroom-context/hooks/useSelectedCategory.ts +7 -0
- package/src/newsroom-context/hooks/useSelectedStory.ts +7 -0
- package/src/newsroom-context/index.ts +2 -0
- package/src/types.ts +56 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import PrezlySDK, {
|
|
2
|
+
Category,
|
|
3
|
+
ExtraStoryFields,
|
|
4
|
+
Newsroom,
|
|
5
|
+
NewsroomLanguageSettings,
|
|
6
|
+
Story,
|
|
7
|
+
} from '@prezly/sdk';
|
|
8
|
+
import type { IncomingMessage } from 'http';
|
|
9
|
+
|
|
10
|
+
import { LocaleObject } from '../../intl';
|
|
11
|
+
import { BasePageProps } from '../../types';
|
|
12
|
+
import { DEFAULT_PAGE_SIZE } from '../constants';
|
|
13
|
+
import { getAlgoliaSettings } from '../lib/getAlgoliaSettings';
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
getCompanyInformation,
|
|
17
|
+
getDefaultLanguage,
|
|
18
|
+
getLanguageFromNextLocaleIsoCode,
|
|
19
|
+
getLanguageFromStory,
|
|
20
|
+
getShortestLocaleCode,
|
|
21
|
+
} from './languages';
|
|
22
|
+
import {
|
|
23
|
+
getContactsQuery,
|
|
24
|
+
getGalleriesQuery,
|
|
25
|
+
getSlugQuery,
|
|
26
|
+
getSortByPublishedDate,
|
|
27
|
+
getStoriesQuery,
|
|
28
|
+
} from './queries';
|
|
29
|
+
|
|
30
|
+
const DEFAULT_SORT_ORDER: SortOrder = 'desc';
|
|
31
|
+
|
|
32
|
+
type SortOrder = 'desc' | 'asc';
|
|
33
|
+
|
|
34
|
+
interface GetStoriesOptions {
|
|
35
|
+
page?: number;
|
|
36
|
+
pageSize?: number;
|
|
37
|
+
order?: SortOrder;
|
|
38
|
+
include?: (keyof ExtraStoryFields)[];
|
|
39
|
+
localeCode?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface GetGalleriesOptions {
|
|
43
|
+
page?: number;
|
|
44
|
+
pageSize: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class PrezlyApi {
|
|
48
|
+
private readonly sdk: PrezlySDK;
|
|
49
|
+
|
|
50
|
+
private readonly newsroomUuid: Newsroom['uuid'];
|
|
51
|
+
|
|
52
|
+
constructor(accessToken: string, newsroomUuid: Newsroom['uuid']) {
|
|
53
|
+
const baseUrl = process.env.API_BASE_URL_OVERRIDE ?? undefined;
|
|
54
|
+
this.sdk = new PrezlySDK({
|
|
55
|
+
accessToken,
|
|
56
|
+
baseUrl,
|
|
57
|
+
headers: { 'X-Convert-v1-To-v3': 'true' },
|
|
58
|
+
});
|
|
59
|
+
this.newsroomUuid = newsroomUuid;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getStory(uuid: string) {
|
|
63
|
+
return this.sdk.stories.get(uuid);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async getNewsroom() {
|
|
67
|
+
return this.sdk.newsrooms.get(this.newsroomUuid);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async getNewsroomContacts() {
|
|
71
|
+
return this.sdk.newsroomContacts.search(this.newsroomUuid, {
|
|
72
|
+
query: JSON.stringify(getContactsQuery()),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async getNewsroomLanguages(): Promise<NewsroomLanguageSettings[]> {
|
|
77
|
+
return (await this.sdk.newsroomLanguages.list(this.newsroomUuid)).languages;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async getAllStories(order: SortOrder = DEFAULT_SORT_ORDER) {
|
|
81
|
+
const sortOrder = getSortByPublishedDate(order);
|
|
82
|
+
const newsroom = await this.getNewsroom();
|
|
83
|
+
const jsonQuery = JSON.stringify(getStoriesQuery(newsroom.uuid));
|
|
84
|
+
const maxStories = newsroom.stories_number;
|
|
85
|
+
const chunkSize = 200;
|
|
86
|
+
|
|
87
|
+
const pages = Math.ceil(maxStories / chunkSize);
|
|
88
|
+
const storiesPromises = Array.from({ length: pages }, (_, pageIndex) =>
|
|
89
|
+
this.searchStories({
|
|
90
|
+
limit: chunkSize,
|
|
91
|
+
sortOrder,
|
|
92
|
+
jsonQuery,
|
|
93
|
+
offset: pageIndex * chunkSize,
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const stories = (await Promise.all(storiesPromises)).flatMap(
|
|
98
|
+
(response) => response.stories,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
return stories;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async getStories({
|
|
105
|
+
page = undefined,
|
|
106
|
+
pageSize = DEFAULT_PAGE_SIZE,
|
|
107
|
+
order = DEFAULT_SORT_ORDER,
|
|
108
|
+
include,
|
|
109
|
+
localeCode,
|
|
110
|
+
}: GetStoriesOptions = {}) {
|
|
111
|
+
const sortOrder = getSortByPublishedDate(order);
|
|
112
|
+
const jsonQuery = JSON.stringify(getStoriesQuery(this.newsroomUuid, undefined, localeCode));
|
|
113
|
+
|
|
114
|
+
const { stories, pagination } = await this.searchStories({
|
|
115
|
+
limit: pageSize,
|
|
116
|
+
offset: typeof page === 'undefined' ? undefined : (page - 1) * pageSize,
|
|
117
|
+
sortOrder,
|
|
118
|
+
jsonQuery,
|
|
119
|
+
include,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const storiesTotal = pagination.matched_records_number;
|
|
123
|
+
|
|
124
|
+
return { stories, storiesTotal };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async getStoriesFromCategory(
|
|
128
|
+
category: Category,
|
|
129
|
+
{
|
|
130
|
+
page = undefined,
|
|
131
|
+
pageSize = DEFAULT_PAGE_SIZE,
|
|
132
|
+
order = DEFAULT_SORT_ORDER,
|
|
133
|
+
include,
|
|
134
|
+
localeCode,
|
|
135
|
+
}: GetStoriesOptions = {},
|
|
136
|
+
) {
|
|
137
|
+
const sortOrder = getSortByPublishedDate(order);
|
|
138
|
+
const jsonQuery = JSON.stringify(
|
|
139
|
+
getStoriesQuery(this.newsroomUuid, category.id, localeCode),
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const { stories, pagination } = await this.searchStories({
|
|
143
|
+
limit: pageSize,
|
|
144
|
+
offset: typeof page === 'undefined' ? undefined : (page - 1) * pageSize,
|
|
145
|
+
sortOrder,
|
|
146
|
+
jsonQuery,
|
|
147
|
+
include,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const storiesTotal = pagination.matched_records_number;
|
|
151
|
+
|
|
152
|
+
return { stories, storiesTotal };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async getStoryBySlug(slug: string) {
|
|
156
|
+
const jsonQuery = JSON.stringify(getSlugQuery(this.newsroomUuid, slug));
|
|
157
|
+
const { stories } = await this.searchStories({
|
|
158
|
+
limit: 1,
|
|
159
|
+
jsonQuery,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (stories[0]) {
|
|
163
|
+
return this.getStory(stories[0].uuid);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async getCategories(): Promise<Category[]> {
|
|
170
|
+
const categories = await this.sdk.newsroomCategories.list(this.newsroomUuid);
|
|
171
|
+
|
|
172
|
+
return Array.isArray(categories) ? categories : Object.values(categories);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async getCategoryBySlug(slug: string) {
|
|
176
|
+
const categories = await this.getCategories();
|
|
177
|
+
|
|
178
|
+
return categories.find((category) =>
|
|
179
|
+
Object.values(category.i18n).some((t) => t.slug === slug),
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
searchStories: typeof PrezlySDK.prototype.stories.search = (options) =>
|
|
184
|
+
this.sdk.stories.search(options);
|
|
185
|
+
|
|
186
|
+
async getGalleries({ page = undefined, pageSize }: GetGalleriesOptions) {
|
|
187
|
+
return this.sdk.newsroomGalleries.list(this.newsroomUuid, {
|
|
188
|
+
limit: pageSize,
|
|
189
|
+
offset: typeof page === 'undefined' ? undefined : (page - 1) * pageSize,
|
|
190
|
+
scope: getGalleriesQuery(),
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async getGallery(uuid: string) {
|
|
195
|
+
return this.sdk.newsroomGalleries.get(this.newsroomUuid, uuid);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async getThemePreset() {
|
|
199
|
+
return this.sdk.newsroomThemes.getActive(this.newsroomUuid);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async getBasePageProps(
|
|
203
|
+
request: IncomingMessage | undefined,
|
|
204
|
+
nextLocaleIsoCode?: string,
|
|
205
|
+
story?: Story,
|
|
206
|
+
): Promise<BasePageProps> {
|
|
207
|
+
const [newsroom, languages, categories, themePreset] = await Promise.all([
|
|
208
|
+
this.getNewsroom(),
|
|
209
|
+
this.getNewsroomLanguages(),
|
|
210
|
+
this.getCategories(),
|
|
211
|
+
this.getThemePreset(),
|
|
212
|
+
]);
|
|
213
|
+
|
|
214
|
+
const currentLanguage = story
|
|
215
|
+
? getLanguageFromStory(languages, story)
|
|
216
|
+
: getLanguageFromNextLocaleIsoCode(languages, nextLocaleIsoCode);
|
|
217
|
+
const defaultLanguage = getDefaultLanguage(languages);
|
|
218
|
+
|
|
219
|
+
const { code: localeCode } = currentLanguage || defaultLanguage;
|
|
220
|
+
const locale = LocaleObject.fromAnyCode(localeCode);
|
|
221
|
+
const shortestLocaleCode = getShortestLocaleCode(languages, locale);
|
|
222
|
+
|
|
223
|
+
// TODO: if no information given for current language, show boilerplate from default language
|
|
224
|
+
const companyInformation = getCompanyInformation(languages, locale);
|
|
225
|
+
|
|
226
|
+
const algoliaSettings = getAlgoliaSettings(request);
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
newsroom,
|
|
230
|
+
companyInformation,
|
|
231
|
+
categories,
|
|
232
|
+
languages,
|
|
233
|
+
localeCode,
|
|
234
|
+
shortestLocaleCode,
|
|
235
|
+
localeResolved: Boolean(currentLanguage),
|
|
236
|
+
themePreset,
|
|
237
|
+
algoliaSettings,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IncomingMessage } from 'http';
|
|
2
|
+
|
|
3
|
+
import { getEnvVariables } from '../lib/getEnvVariables';
|
|
4
|
+
|
|
5
|
+
import { PrezlyApi } from './PrezlyApi';
|
|
6
|
+
|
|
7
|
+
export const getPrezlyApi = (req?: IncomingMessage): PrezlyApi => {
|
|
8
|
+
if (process.browser) {
|
|
9
|
+
throw new Error('"getPrezlyApi" should only be used on back-end side.');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// `getEnvVariables` handles both cases for envs parsing - .env and request headers
|
|
13
|
+
const { PREZLY_ACCESS_TOKEN, PREZLY_NEWSROOM_UUID } = getEnvVariables(req);
|
|
14
|
+
|
|
15
|
+
if (!PREZLY_ACCESS_TOKEN) {
|
|
16
|
+
throw new Error('"PREZLY_ACCESS_TOKEN" is not set in env variables.');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!PREZLY_NEWSROOM_UUID) {
|
|
20
|
+
throw new Error('"PREZLY_NEWSROOM_UUID" is not set in env variables.');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return new PrezlyApi(PREZLY_ACCESS_TOKEN, PREZLY_NEWSROOM_UUID);
|
|
24
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { NewsroomLanguageSettings, Story } from '@prezly/sdk';
|
|
2
|
+
|
|
3
|
+
import { DUMMY_DEFAULT_LOCALE, LocaleObject } from '../../intl';
|
|
4
|
+
|
|
5
|
+
export function getDefaultLanguage(languages: NewsroomLanguageSettings[]) {
|
|
6
|
+
return languages.find(({ is_default }) => is_default) || languages[0];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getUsedLanguages(languages: NewsroomLanguageSettings[]) {
|
|
10
|
+
return languages.filter((language) => language.public_stories_count > 0);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function getLanguageByExactLocaleCode(languages: NewsroomLanguageSettings[], locale: LocaleObject) {
|
|
14
|
+
const localeCode = locale.toUnderscoreCode();
|
|
15
|
+
return languages.find(({ code }) => code === localeCode);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// See https://github.com/prezly/prezly/blob/master/lib/model/CulturePeer.php#L123
|
|
19
|
+
function getLanguageByNeutralLocaleCode(
|
|
20
|
+
languages: NewsroomLanguageSettings[],
|
|
21
|
+
locale: LocaleObject,
|
|
22
|
+
) {
|
|
23
|
+
const neutralLanguageCode = locale.toNeutralLanguageCode();
|
|
24
|
+
|
|
25
|
+
// Prefer default language
|
|
26
|
+
const defaultLanguage = getDefaultLanguage(languages);
|
|
27
|
+
if (defaultLanguage.code === locale.toUnderscoreCode()) {
|
|
28
|
+
return defaultLanguage;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Try to look in used cultures first (giving priority to used ones)
|
|
32
|
+
const usedLanguages = getUsedLanguages(languages);
|
|
33
|
+
const usedLanguage = usedLanguages.find(
|
|
34
|
+
({ code }) =>
|
|
35
|
+
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() === neutralLanguageCode ||
|
|
36
|
+
code === neutralLanguageCode,
|
|
37
|
+
);
|
|
38
|
+
if (usedLanguage) {
|
|
39
|
+
return usedLanguage;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Search in all languages
|
|
43
|
+
return languages.find(
|
|
44
|
+
({ code }) =>
|
|
45
|
+
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() === neutralLanguageCode ||
|
|
46
|
+
code === neutralLanguageCode,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// See https://github.com/prezly/prezly/blob/master/lib/model/CulturePeer.php#L159
|
|
51
|
+
function getLanguageByShortRegionCode(languages: NewsroomLanguageSettings[], locale: LocaleObject) {
|
|
52
|
+
const shortRegionCode = locale.toRegionCode();
|
|
53
|
+
|
|
54
|
+
// Prefer default language
|
|
55
|
+
const defaultLanguage = getDefaultLanguage(languages);
|
|
56
|
+
if (LocaleObject.fromAnyCode(defaultLanguage.code).toRegionCode() === shortRegionCode) {
|
|
57
|
+
return defaultLanguage;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Try to look in used cultures first (giving priority to used ones)
|
|
61
|
+
const usedLanguages = getUsedLanguages(languages);
|
|
62
|
+
const usedLanguage = usedLanguages.find(
|
|
63
|
+
({ code }) => LocaleObject.fromAnyCode(code).toRegionCode() === shortRegionCode,
|
|
64
|
+
);
|
|
65
|
+
if (usedLanguage) {
|
|
66
|
+
return usedLanguage;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Search in all languages
|
|
70
|
+
return languages.find(
|
|
71
|
+
({ code }) => LocaleObject.fromAnyCode(code).toRegionCode() === shortRegionCode,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Retrieve a culture with fallback to legacy codes support.
|
|
77
|
+
* Pulled from https://github.com/prezly/prezly/blob/de9900d9890a33502780494aa3fb85c9a732b3c3/lib/model/CulturePeer.php#L91-L114
|
|
78
|
+
*/
|
|
79
|
+
export function getLanguageFromNextLocaleIsoCode(
|
|
80
|
+
languages: NewsroomLanguageSettings[],
|
|
81
|
+
nextLocaleIsoCode?: string,
|
|
82
|
+
): NewsroomLanguageSettings | undefined {
|
|
83
|
+
const defaultLanguage = getDefaultLanguage(languages);
|
|
84
|
+
|
|
85
|
+
if (!nextLocaleIsoCode || nextLocaleIsoCode === DUMMY_DEFAULT_LOCALE) {
|
|
86
|
+
return defaultLanguage;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const locale = LocaleObject.fromAnyCode(nextLocaleIsoCode);
|
|
90
|
+
let targetLanguage: NewsroomLanguageSettings | undefined;
|
|
91
|
+
|
|
92
|
+
if (nextLocaleIsoCode.length === 2) {
|
|
93
|
+
targetLanguage =
|
|
94
|
+
getLanguageByExactLocaleCode(languages, locale) ||
|
|
95
|
+
getLanguageByNeutralLocaleCode(languages, locale) ||
|
|
96
|
+
getLanguageByShortRegionCode(languages, locale);
|
|
97
|
+
if (targetLanguage) {
|
|
98
|
+
return targetLanguage;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
targetLanguage = getLanguageByExactLocaleCode(languages, locale);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return targetLanguage;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function getLanguageFromStory(languages: NewsroomLanguageSettings[], story: Story) {
|
|
108
|
+
const { code: storyLocaleCode } = story.culture;
|
|
109
|
+
|
|
110
|
+
return languages.find(({ code }) => code === storyLocaleCode);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function getCompanyInformation(languages: NewsroomLanguageSettings[], locale: LocaleObject) {
|
|
114
|
+
const currentLanguage =
|
|
115
|
+
getLanguageByExactLocaleCode(languages, locale) || getDefaultLanguage(languages);
|
|
116
|
+
|
|
117
|
+
return currentLanguage.company_information;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get shortest locale code possible from full locale code
|
|
122
|
+
* First: try shorting to neutral language code (there should be no locales with the same language code)
|
|
123
|
+
* Then: try shorting to region code (there should be no locales with the same region code)
|
|
124
|
+
* Finally: return the original locale code (shorting is not possible)
|
|
125
|
+
*/
|
|
126
|
+
export function getShortestLocaleCode(
|
|
127
|
+
languages: NewsroomLanguageSettings[],
|
|
128
|
+
locale: LocaleObject,
|
|
129
|
+
): string | false {
|
|
130
|
+
const localeCode = locale.toUnderscoreCode();
|
|
131
|
+
const defaultLanguage = getDefaultLanguage(languages);
|
|
132
|
+
// If it's a default locale, return false (no locale needed in URL)
|
|
133
|
+
if (localeCode === defaultLanguage.code) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Try shorting to neutral language code
|
|
138
|
+
const neutralLanguageCode = locale.toNeutralLanguageCode();
|
|
139
|
+
// The code is already as short as possible
|
|
140
|
+
if (neutralLanguageCode === localeCode) {
|
|
141
|
+
return localeCode;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const matchingLanguagesByNeutralCode = languages.filter(
|
|
145
|
+
({ code }) =>
|
|
146
|
+
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() === neutralLanguageCode ||
|
|
147
|
+
code === neutralLanguageCode,
|
|
148
|
+
);
|
|
149
|
+
if (matchingLanguagesByNeutralCode.length === 1) {
|
|
150
|
+
return neutralLanguageCode;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Try shorting to region code
|
|
154
|
+
const shortRegionCode = locale.toRegionCode();
|
|
155
|
+
const matchingLanguagesByRegionCode = languages.filter(
|
|
156
|
+
({ code }) => LocaleObject.fromAnyCode(code).toRegionCode() === shortRegionCode,
|
|
157
|
+
);
|
|
158
|
+
// Prevent collision with neutral language codes
|
|
159
|
+
const mathchingNeutralLanguagesByRegionCode = languages.filter(
|
|
160
|
+
({ code }) =>
|
|
161
|
+
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() === shortRegionCode ||
|
|
162
|
+
code === shortRegionCode,
|
|
163
|
+
);
|
|
164
|
+
if (
|
|
165
|
+
matchingLanguagesByRegionCode.length === 1 &&
|
|
166
|
+
!mathchingNeutralLanguagesByRegionCode.length
|
|
167
|
+
) {
|
|
168
|
+
return shortRegionCode;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return localeCode;
|
|
172
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const publishedAndAccessible = [
|
|
2
|
+
{ lifecycle_status: { $in: ['published'] } },
|
|
3
|
+
{ visibility: { $in: ['public', 'private'] } },
|
|
4
|
+
];
|
|
5
|
+
|
|
6
|
+
const publishedAndPublic = [
|
|
7
|
+
{ lifecycle_status: { $in: ['published'] } },
|
|
8
|
+
{ visibility: { $in: ['public'] } },
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export const getSlugQuery = (newsroomUuid: string, slug: string) => ({
|
|
12
|
+
$and: [
|
|
13
|
+
{ 'newsroom.uuid': { $in: [newsroomUuid] } },
|
|
14
|
+
{ slug: { $eq: slug } },
|
|
15
|
+
...publishedAndAccessible,
|
|
16
|
+
],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const getStoriesQuery = (newsroomUuid: string, categoryId?: number, localeCode?: string) => {
|
|
20
|
+
const query: any = {
|
|
21
|
+
$and: [...publishedAndPublic, { 'newsroom.uuid': { $in: [newsroomUuid] } }],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
if (categoryId) {
|
|
25
|
+
query.$and.push({ 'category.id': { $any: [categoryId] } });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (localeCode) {
|
|
29
|
+
query.$and.push({ locale: { $in: [localeCode] } });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return query;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const getSortByPublishedDate = (order: 'asc' | 'desc') =>
|
|
36
|
+
order === 'desc' ? '-published_at' : 'published_at';
|
|
37
|
+
|
|
38
|
+
export const getGalleriesQuery = () => ({
|
|
39
|
+
$and: [{ status: { $eq: 'public' } }, { images_number: { $gt: 0 } }],
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export const getContactsQuery = () => ({
|
|
43
|
+
$and: [{ is_featured: { $eq: true } }],
|
|
44
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Category } from '@prezly/sdk';
|
|
2
|
+
|
|
3
|
+
import { LocaleObject } from '../intl';
|
|
4
|
+
import { AlgoliaCategoryRef } from '../types';
|
|
5
|
+
|
|
6
|
+
function isAlgoliaCategory(
|
|
7
|
+
category: Category | AlgoliaCategoryRef,
|
|
8
|
+
): category is AlgoliaCategoryRef {
|
|
9
|
+
return 'name' in category && 'slug' in category;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getLocalizedCategoryData(
|
|
13
|
+
category: Category | AlgoliaCategoryRef,
|
|
14
|
+
locale: LocaleObject,
|
|
15
|
+
) {
|
|
16
|
+
if (isAlgoliaCategory(category)) {
|
|
17
|
+
return {
|
|
18
|
+
description: null,
|
|
19
|
+
name: category.name,
|
|
20
|
+
slug: category.slug,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const targetLocaleCode = locale.toUnderscoreCode();
|
|
25
|
+
const { i18n } = category;
|
|
26
|
+
const populatedLocales = Object.keys(i18n).filter((localeCode) => i18n[localeCode].name);
|
|
27
|
+
const targetLocale =
|
|
28
|
+
populatedLocales.find((localeCode) => localeCode === targetLocaleCode) ||
|
|
29
|
+
populatedLocales.find((localeCode) => i18n[localeCode].name === category.display_name) ||
|
|
30
|
+
populatedLocales[0];
|
|
31
|
+
|
|
32
|
+
const { locale: _, ...localizedData } = i18n[targetLocale];
|
|
33
|
+
|
|
34
|
+
return localizedData;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getCategoryUrl(category: Category | AlgoliaCategoryRef, locale: LocaleObject) {
|
|
38
|
+
const { slug } = getLocalizedCategoryData(category, locale);
|
|
39
|
+
return `/category/${slug}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getCategoryHasTranslation(category: Category, locale: LocaleObject) {
|
|
43
|
+
const targetLocaleCode = locale.toUnderscoreCode();
|
|
44
|
+
const { i18n } = category;
|
|
45
|
+
const populatedLocales = Object.keys(i18n).filter((localeCode) => i18n[localeCode].name);
|
|
46
|
+
return Boolean(populatedLocales.find((localeCode) => localeCode === targetLocaleCode));
|
|
47
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Newsroom } from '@prezly/sdk';
|
|
2
|
+
|
|
3
|
+
import { getAssetsUrl } from './getAssetsUrl';
|
|
4
|
+
|
|
5
|
+
export function getNewsroomLogoUrl(newsroom: Newsroom): string {
|
|
6
|
+
if (newsroom.newsroom_logo) {
|
|
7
|
+
getAssetsUrl(newsroom.newsroom_logo.uuid);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getNewsroomFaviconUrl(newsroom: Newsroom, previewSize = 400): string {
|
|
14
|
+
if (newsroom.icon) {
|
|
15
|
+
return `${getAssetsUrl(
|
|
16
|
+
newsroom.icon.uuid,
|
|
17
|
+
)}-/preview/${previewSize}x${previewSize}/-/quality/best/`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Newsroom } from '@prezly/sdk';
|
|
2
|
+
|
|
3
|
+
import { LocaleObject } from '../intl';
|
|
4
|
+
|
|
5
|
+
type PrivacyPortalUrlOptions = { email?: string; action?: 'subscribe' | 'unsubscribe' };
|
|
6
|
+
|
|
7
|
+
export function getPrivacyPortalUrl(
|
|
8
|
+
newsroom: Newsroom,
|
|
9
|
+
locale: LocaleObject,
|
|
10
|
+
options?: PrivacyPortalUrlOptions,
|
|
11
|
+
) {
|
|
12
|
+
const { email, action = 'subscribe' } = options || {};
|
|
13
|
+
|
|
14
|
+
const url = new URL(
|
|
15
|
+
`/${locale.toUrlSlug()}/newsroom/${newsroom.uuid}/${action}`,
|
|
16
|
+
'https://privacy.prezly.com',
|
|
17
|
+
);
|
|
18
|
+
if (email) {
|
|
19
|
+
url.searchParams.append('email', email);
|
|
20
|
+
}
|
|
21
|
+
return url.toString();
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Story } from '@prezly/sdk';
|
|
2
|
+
|
|
3
|
+
import { AlgoliaStory } from '../types';
|
|
4
|
+
|
|
5
|
+
export function getStoryPublicationDate(story: Story | AlgoliaStory): Date | null {
|
|
6
|
+
const { published_at } = story;
|
|
7
|
+
|
|
8
|
+
if (!published_at) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return typeof published_at === 'string'
|
|
13
|
+
? new Date(published_at)
|
|
14
|
+
: new Date(published_at * 1000);
|
|
15
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './api';
|
|
2
|
+
export * from './constants';
|
|
3
|
+
export * from './getAssetsUrl';
|
|
4
|
+
export * from './getLocalizedCategoryData';
|
|
5
|
+
export * from './getNewsroomLogoUrl';
|
|
6
|
+
export * from './getPrivacyPortalUrl';
|
|
7
|
+
export * from './getStoryPublicationDate';
|
|
8
|
+
export * from './getUploadcareGroupUrl';
|
|
9
|
+
export * from './types';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { IncomingMessage } from 'http';
|
|
2
|
+
|
|
3
|
+
import { AlgoliaSettings } from '../types';
|
|
4
|
+
|
|
5
|
+
import { getEnvVariables } from './getEnvVariables';
|
|
6
|
+
|
|
7
|
+
export const getAlgoliaSettings = (req?: IncomingMessage): AlgoliaSettings => {
|
|
8
|
+
if (process.browser) {
|
|
9
|
+
throw new Error('"getAlgoliaSettings" should only be used on back-end side.');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// `getEnvVariables` handles both cases for envs parsing - .env and request headers
|
|
13
|
+
const {
|
|
14
|
+
ALGOLIA_API_KEY = '',
|
|
15
|
+
ALGOLIA_APP_ID = 'UI4CNRAHQB',
|
|
16
|
+
ALGOLIA_INDEX = 'public_stories_prod',
|
|
17
|
+
} = getEnvVariables(req);
|
|
18
|
+
|
|
19
|
+
if (!ALGOLIA_API_KEY) {
|
|
20
|
+
// eslint-disable-next-line no-console
|
|
21
|
+
console.error('"ALGOLIA_API_KEY" is not set in env variables. Search will not be enabled');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
ALGOLIA_API_KEY,
|
|
26
|
+
ALGOLIA_APP_ID,
|
|
27
|
+
ALGOLIA_INDEX,
|
|
28
|
+
};
|
|
29
|
+
};
|