@griddo/cx 1.75.178 → 1.75.180
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 +22 -14
- package/build/index.js +49 -0
- package/gatsby-browser.tsx +140 -0
- package/gatsby-config.ts +40 -0
- package/gatsby-node.ts +130 -0
- package/gatsby-ssr.tsx +63 -0
- package/index.js +4 -0
- package/package.json +119 -100
- package/scripts/build-reset.ts +9 -0
- package/scripts/griddo-exporter.ts +302 -0
- package/src/components/Head.tsx +207 -0
- package/src/components/template.tsx +90 -0
- package/src/components/types.ts +35 -0
- package/src/components/utils.ts +138 -0
- package/src/html.tsx +31 -0
- package/src/services/auth.ts +64 -0
- package/src/services/distributors.ts +153 -0
- package/src/services/domains.ts +27 -0
- package/src/services/navigation.ts +169 -0
- package/src/services/robots.ts +64 -0
- package/src/services/settings.ts +52 -0
- package/src/services/sites.ts +199 -0
- package/src/services/store-with-for-loop.ts +513 -0
- package/src/services/store-with-promise-all.ts +515 -0
- package/src/services/store.ts +513 -0
- package/src/types/api.ts +155 -0
- package/src/types/global.ts +72 -0
- package/src/types/navigation.ts +25 -0
- package/src/types/pages.ts +145 -0
- package/src/types/sites.ts +64 -0
- package/src/types/templates.ts +11 -0
- package/src/utils/api.ts +326 -0
- package/src/utils/cache.ts +114 -0
- package/src/utils/domains.ts +32 -0
- package/src/utils/folders.ts +147 -0
- package/src/utils/instance.ts +71 -0
- package/src/utils/pages.ts +534 -0
- package/src/utils/searches.ts +102 -0
- package/src/utils/shared.ts +131 -0
- package/src/utils/sites.ts +280 -0
- package/.babelrc +0 -7
- package/LICENSE +0 -1
- package/gatsby-browser.js +0 -115
- package/gatsby-config.js +0 -38
- package/gatsby-node.js +0 -273
- package/gatsby-ssr.js +0 -43
- package/scripts/griddo-exporter.js +0 -133
- package/src/api/index.js +0 -172
- package/src/components/template.js +0 -261
- package/src/html.js +0 -30
- package/src/images/readme.md +0 -1
- package/src/scripts/build-reset.js +0 -12
- package/src/services/auth.js +0 -44
- package/src/services/distributors.js +0 -85
- package/src/services/domains.js +0 -16
- package/src/services/navigation.js +0 -104
- package/src/services/robots.js +0 -37
- package/src/services/settings.js +0 -25
- package/src/services/sites.js +0 -110
- package/src/utils/cache.js +0 -70
- package/src/utils/component-lib-helpers.js +0 -56
- package/src/utils/dataLayer.js +0 -47
- package/src/utils/delay.js +0 -5
- package/src/utils/domains.js +0 -24
- package/src/utils/folders.js +0 -123
- package/src/utils/helpers.js +0 -144
- package/src/utils/index.js +0 -44
- package/src/utils/package.js +0 -20
- package/src/utils/pages.js +0 -236
- package/src/utils/searches.js +0 -62
- package/src/utils/sites.js +0 -207
- package/static/griddo-full-logo.png +0 -0
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
// Types
|
|
2
|
+
import type { Core, Fields } from "@griddo/core";
|
|
3
|
+
import type {
|
|
4
|
+
APIPageObject,
|
|
5
|
+
GatsbyPageObject,
|
|
6
|
+
GriddoListPage,
|
|
7
|
+
GriddoMultiPage,
|
|
8
|
+
GriddoSinglePage,
|
|
9
|
+
MultiPageElements,
|
|
10
|
+
PageAdditionalInfo,
|
|
11
|
+
} from "../types/pages";
|
|
12
|
+
import type { TemplateWithDistributor } from "../types/templates";
|
|
13
|
+
|
|
14
|
+
// External libraries
|
|
15
|
+
import dotenv from "dotenv";
|
|
16
|
+
import fs from "fs";
|
|
17
|
+
import path from "path";
|
|
18
|
+
|
|
19
|
+
// Utils
|
|
20
|
+
import { formatImage } from "../components/utils";
|
|
21
|
+
import { postSearchInfo } from "./searches";
|
|
22
|
+
|
|
23
|
+
dotenv.config();
|
|
24
|
+
|
|
25
|
+
// Envs
|
|
26
|
+
const GRIDDO_SEARCH_FEATURE = !!JSON.parse(
|
|
27
|
+
process.env.GRIDDO_SEARCH_FEATURE || "false"
|
|
28
|
+
);
|
|
29
|
+
const HAS_ASSET_PREFIX = !!process.env.GRIDDO_ASSET_PREFIX;
|
|
30
|
+
|
|
31
|
+
// Constants
|
|
32
|
+
const DEFAULT_ITEMS_PER_PAGE_FOR_LIST_TEMPLATES = 25;
|
|
33
|
+
const COMPONENT = path.resolve(__dirname, "../../src/components/template.tsx");
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Return an OpenGraph object.
|
|
37
|
+
*
|
|
38
|
+
* @param props.socialTitle The social title.
|
|
39
|
+
* @param props.socialDescription The social description.
|
|
40
|
+
* @param props.socialImage The social image in Cloudinary or DAM url format.
|
|
41
|
+
*/
|
|
42
|
+
function getOpenGraph({
|
|
43
|
+
socialTitle,
|
|
44
|
+
socialDescription,
|
|
45
|
+
socialImage,
|
|
46
|
+
}: Pick<
|
|
47
|
+
Core.Page,
|
|
48
|
+
"socialTitle" | "socialDescription" | "socialImage"
|
|
49
|
+
>): Core.Page["openGraph"] {
|
|
50
|
+
return {
|
|
51
|
+
type: "website",
|
|
52
|
+
title: socialTitle,
|
|
53
|
+
description: socialDescription,
|
|
54
|
+
image: socialImage ? formatImage(socialImage, 1280, 768) : "",
|
|
55
|
+
twitterImage: socialImage ? formatImage(socialImage, 1280, 768) : "",
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get the Page metadata object from a page Object.
|
|
61
|
+
*
|
|
62
|
+
* @param params A Page object
|
|
63
|
+
*/
|
|
64
|
+
function getPageMetaData(params: Core.Page): Core.Page["pageMetaData"] {
|
|
65
|
+
const {
|
|
66
|
+
title,
|
|
67
|
+
metaTitle,
|
|
68
|
+
metaDescription,
|
|
69
|
+
canonicalURL,
|
|
70
|
+
locale,
|
|
71
|
+
url,
|
|
72
|
+
isIndexed,
|
|
73
|
+
follow,
|
|
74
|
+
metasAdvanced,
|
|
75
|
+
pageLanguages,
|
|
76
|
+
fullUrl,
|
|
77
|
+
} = params;
|
|
78
|
+
|
|
79
|
+
const metasAdvancedList =
|
|
80
|
+
metasAdvanced
|
|
81
|
+
?.split(",")
|
|
82
|
+
.filter(Boolean)
|
|
83
|
+
.map((item) => item.trim().toLowerCase()) || [];
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
title: (metaTitle || title || "").trim(),
|
|
87
|
+
description: metaDescription,
|
|
88
|
+
canonical:
|
|
89
|
+
canonicalURL && canonicalURL.trim() && canonicalURL !== fullUrl
|
|
90
|
+
? canonicalURL.trim()
|
|
91
|
+
: isIndexed
|
|
92
|
+
? fullUrl
|
|
93
|
+
: undefined,
|
|
94
|
+
locale,
|
|
95
|
+
url,
|
|
96
|
+
index: isIndexed ? "index" : "noindex",
|
|
97
|
+
follow: follow ? "follow" : "nofollow",
|
|
98
|
+
translate: metasAdvancedList.includes("notranslate") ? "notranslate" : "",
|
|
99
|
+
metasAdvanced: metasAdvancedList
|
|
100
|
+
.filter((item) => item !== "notranslate")
|
|
101
|
+
.join(),
|
|
102
|
+
pageLanguages,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Create a page object to be processes by Gatsby `createPage()`
|
|
108
|
+
*
|
|
109
|
+
* @param page A page object ready to pass as content of the `pageContext` to use in the React template.
|
|
110
|
+
* @param additionalInfo Additional page info to pass as content of `pageContext` to use in the React template.
|
|
111
|
+
*/
|
|
112
|
+
async function createGatsbyPageObject(
|
|
113
|
+
page: GriddoSinglePage | GriddoListPage | GriddoMultiPage,
|
|
114
|
+
additionalInfo: PageAdditionalInfo
|
|
115
|
+
): Promise<GatsbyPageObject> {
|
|
116
|
+
// Extract some props from page
|
|
117
|
+
const {
|
|
118
|
+
id,
|
|
119
|
+
title,
|
|
120
|
+
fullPath,
|
|
121
|
+
language: languageId,
|
|
122
|
+
breadcrumb,
|
|
123
|
+
socialDescription,
|
|
124
|
+
socialImage,
|
|
125
|
+
socialTitle,
|
|
126
|
+
} = page;
|
|
127
|
+
|
|
128
|
+
// Extract some props from additionalInfo
|
|
129
|
+
const {
|
|
130
|
+
baseUrl,
|
|
131
|
+
BUILD_MODE,
|
|
132
|
+
cloudinaryName,
|
|
133
|
+
griddoVersion,
|
|
134
|
+
siteLangs,
|
|
135
|
+
siteMetadata,
|
|
136
|
+
siteOptions,
|
|
137
|
+
siteScript,
|
|
138
|
+
siteSlug,
|
|
139
|
+
socials,
|
|
140
|
+
theme,
|
|
141
|
+
navigations: { header, footer },
|
|
142
|
+
} = additionalInfo;
|
|
143
|
+
|
|
144
|
+
// Update page object
|
|
145
|
+
page = {
|
|
146
|
+
...page,
|
|
147
|
+
breadcrumb,
|
|
148
|
+
siteSlug,
|
|
149
|
+
apiUrl: baseUrl,
|
|
150
|
+
publicApiUrl: additionalInfo.publicBaseUrl,
|
|
151
|
+
instance: additionalInfo.instance,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const filepath = `${fullPath?.domain}${fullPath?.compose}`;
|
|
155
|
+
const foundLanguage = siteLangs.find(({ id }) => id === page?.language);
|
|
156
|
+
const locale = foundLanguage?.locale.replace(/_/g, "-");
|
|
157
|
+
|
|
158
|
+
// Page Metadata
|
|
159
|
+
const pageMetadata = getPageMetaData(page);
|
|
160
|
+
|
|
161
|
+
// Opengraph
|
|
162
|
+
const openGraph = getOpenGraph({
|
|
163
|
+
socialDescription,
|
|
164
|
+
socialImage,
|
|
165
|
+
socialTitle,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const pageObjectForGatsby = {
|
|
169
|
+
matchPath: "",
|
|
170
|
+
path: filepath,
|
|
171
|
+
component: COMPONENT,
|
|
172
|
+
size: 0,
|
|
173
|
+
context: {
|
|
174
|
+
// Page
|
|
175
|
+
id,
|
|
176
|
+
title,
|
|
177
|
+
fullPath,
|
|
178
|
+
locale,
|
|
179
|
+
languageId,
|
|
180
|
+
theme,
|
|
181
|
+
|
|
182
|
+
// PARA <Helmet />
|
|
183
|
+
siteMetadata,
|
|
184
|
+
pageMetadata,
|
|
185
|
+
openGraph,
|
|
186
|
+
socials,
|
|
187
|
+
siteLangs,
|
|
188
|
+
cloudinaryName,
|
|
189
|
+
siteOptions,
|
|
190
|
+
BUILD_MODE,
|
|
191
|
+
griddoVersion,
|
|
192
|
+
siteScript,
|
|
193
|
+
|
|
194
|
+
// Navigation sections
|
|
195
|
+
header,
|
|
196
|
+
footer,
|
|
197
|
+
|
|
198
|
+
// Page template
|
|
199
|
+
page,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const assetPrefix =
|
|
204
|
+
fullPath?.domain.startsWith("/pro-") && HAS_ASSET_PREFIX
|
|
205
|
+
? process.env.GRIDDO_ASSET_PREFIX
|
|
206
|
+
: undefined;
|
|
207
|
+
|
|
208
|
+
if (assetPrefix) {
|
|
209
|
+
pageObjectForGatsby.matchPath = fullPath?.compose as string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (GRIDDO_SEARCH_FEATURE) {
|
|
213
|
+
const exportFile = path.resolve(
|
|
214
|
+
__dirname,
|
|
215
|
+
"../../dist/",
|
|
216
|
+
`./${filepath}index.html`
|
|
217
|
+
);
|
|
218
|
+
const content = fs.existsSync(exportFile)
|
|
219
|
+
? fs.readFileSync(exportFile).toString()
|
|
220
|
+
: "";
|
|
221
|
+
|
|
222
|
+
await postSearchInfo({
|
|
223
|
+
title,
|
|
224
|
+
description: openGraph.description || "",
|
|
225
|
+
image: openGraph.image || "",
|
|
226
|
+
pageId: id,
|
|
227
|
+
languageId,
|
|
228
|
+
// Dont know if page.template_id is something old
|
|
229
|
+
// template: page.template_id || page?.template?.templateType || null,
|
|
230
|
+
template: page?.template?.templateType || null,
|
|
231
|
+
siteId: page.site,
|
|
232
|
+
url: page.fullUrl,
|
|
233
|
+
content,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return pageObjectForGatsby;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Create a single Griddo page object.
|
|
242
|
+
*
|
|
243
|
+
* @param page A Griddo single page object.
|
|
244
|
+
* @param additionalInfo Additional page info.
|
|
245
|
+
*/
|
|
246
|
+
async function createGriddoSinglePage(
|
|
247
|
+
page: GriddoSinglePage,
|
|
248
|
+
additionalInfo: PageAdditionalInfo
|
|
249
|
+
) {
|
|
250
|
+
return await createGatsbyPageObject(page, additionalInfo);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Create multiples pages from one page as list paginated pages
|
|
255
|
+
*/
|
|
256
|
+
async function createGriddoListPages(
|
|
257
|
+
{
|
|
258
|
+
page,
|
|
259
|
+
pages,
|
|
260
|
+
isRoot = false,
|
|
261
|
+
defaultLang,
|
|
262
|
+
template,
|
|
263
|
+
totalQueriedItems,
|
|
264
|
+
}: GriddoListPage,
|
|
265
|
+
additionalInfo: PageAdditionalInfo
|
|
266
|
+
) {
|
|
267
|
+
const allPages = pages.map(async (dataInPage, idx) => {
|
|
268
|
+
const isFirstPage = idx === 0;
|
|
269
|
+
const pageNumber = idx + 1;
|
|
270
|
+
const { domainUrl, compose } = page.fullPath;
|
|
271
|
+
|
|
272
|
+
const paginatedPage = {
|
|
273
|
+
...page,
|
|
274
|
+
fullPath: {
|
|
275
|
+
...page.fullPath,
|
|
276
|
+
// Add a page number (tailPageNumber) from page 2 onwards
|
|
277
|
+
compose: addPageNumberToUrl(compose, pageNumber, {
|
|
278
|
+
addEndingSlash: true,
|
|
279
|
+
}),
|
|
280
|
+
},
|
|
281
|
+
fullUrl: addPageNumberToUrl(page.fullUrl, pageNumber, {
|
|
282
|
+
addEndingSlash: true,
|
|
283
|
+
}),
|
|
284
|
+
slug: addPageNumberToUrl(page.slug, pageNumber),
|
|
285
|
+
title: addPageNumberToTitle(page.title, pageNumber),
|
|
286
|
+
metaTitle: addPageNumberToTitle(page.metaTitle || "", pageNumber),
|
|
287
|
+
disableHrefLangs: pageNumber > 1,
|
|
288
|
+
template: {
|
|
289
|
+
...template,
|
|
290
|
+
isFirstPage,
|
|
291
|
+
pageNumber,
|
|
292
|
+
totalPages: pages.length,
|
|
293
|
+
// The base link, without page number to use in <Pagination />
|
|
294
|
+
// component.
|
|
295
|
+
baseLink: `${domainUrl}${compose}`,
|
|
296
|
+
queriedItems: dataInPage,
|
|
297
|
+
totalQueriedItems: totalQueriedItems?.length,
|
|
298
|
+
},
|
|
299
|
+
isRoot,
|
|
300
|
+
defaultLang,
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
return await createGatsbyPageObject(paginatedPage, additionalInfo);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
return Promise.all(allPages);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Create multiples pages from a MultiPage module
|
|
311
|
+
*
|
|
312
|
+
* @param page A Griddo Multipage object.
|
|
313
|
+
* @param additionalInfo Additional page info.
|
|
314
|
+
*/
|
|
315
|
+
function createGriddoMultiPages(
|
|
316
|
+
page: GriddoMultiPage,
|
|
317
|
+
additionalInfo: PageAdditionalInfo
|
|
318
|
+
) {
|
|
319
|
+
const { multiPageElements: multiPageElementsBulk, ...cleanPage } = page;
|
|
320
|
+
// TODO: Use structuredClone() when node 18 is available.
|
|
321
|
+
const multiPageElements: MultiPageElements = JSON.parse(
|
|
322
|
+
JSON.stringify(multiPageElementsBulk)
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
// si no hay un elemento sin slug, como mínimo hay que dibujar una página principal para el conjunto de páginas
|
|
326
|
+
if (
|
|
327
|
+
!multiPageElements.find(
|
|
328
|
+
({ sectionSlug }: { sectionSlug: string }) => sectionSlug === "/"
|
|
329
|
+
)
|
|
330
|
+
) {
|
|
331
|
+
// @ts-expect-error
|
|
332
|
+
multiPageElements.push({});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Creates each page based on `multiPageElements` from the schema.
|
|
336
|
+
const allPages = multiPageElements.map(async (pageElement) => {
|
|
337
|
+
// TODO: Use structuredClone() when node 18 is available.
|
|
338
|
+
const paginatedPage: APIPageObject = JSON.parse(JSON.stringify(cleanPage));
|
|
339
|
+
const {
|
|
340
|
+
sectionSlug = "/",
|
|
341
|
+
title: bulkTitle = "",
|
|
342
|
+
metaTitle = "",
|
|
343
|
+
metaDescription = "",
|
|
344
|
+
} = pageElement;
|
|
345
|
+
const title = typeof bulkTitle === "string" ? bulkTitle : bulkTitle.content;
|
|
346
|
+
const compose = paginatedPage.fullPath.compose || "";
|
|
347
|
+
const fullUrl = paginatedPage.fullUrl.endsWith("/")
|
|
348
|
+
? paginatedPage.fullUrl.slice(0, -1)
|
|
349
|
+
: paginatedPage.fullUrl;
|
|
350
|
+
const rightSectionSlug = sectionSlug?.replace(/\//g, "");
|
|
351
|
+
const slash = compose.endsWith("/") ? "" : "/";
|
|
352
|
+
const newCompose = `${compose}${slash}${rightSectionSlug}`;
|
|
353
|
+
|
|
354
|
+
if (title.trim()) {
|
|
355
|
+
paginatedPage.title = title;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (metaDescription.trim()) {
|
|
359
|
+
paginatedPage.metaDescription = metaDescription;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
paginatedPage.fullUrl = `${fullUrl}/${rightSectionSlug}`;
|
|
363
|
+
paginatedPage.fullPath.compose = newCompose;
|
|
364
|
+
paginatedPage.slug = newCompose;
|
|
365
|
+
paginatedPage.template.activeSectionSlug = sectionSlug;
|
|
366
|
+
paginatedPage.template.activeSectionBase = fullUrl;
|
|
367
|
+
paginatedPage.metaTitle =
|
|
368
|
+
metaTitle.trim() || title.trim() || paginatedPage.metaTitle;
|
|
369
|
+
|
|
370
|
+
return await createGatsbyPageObject(paginatedPage, additionalInfo);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
return Promise.all(allPages);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Get the multi pages elements.
|
|
378
|
+
*
|
|
379
|
+
* @param page The page to get the multipage parts.
|
|
380
|
+
*/
|
|
381
|
+
function getMultiPageElements(page: TemplateWithDistributor) {
|
|
382
|
+
const multiPageElements = new Promise((resolve) => {
|
|
383
|
+
// Recursive
|
|
384
|
+
const getMultiPageComponent = (
|
|
385
|
+
// No puede ser Core.Page['template'] porque a medida que va bajando en
|
|
386
|
+
// el árbol ya no es la estructura de un template.
|
|
387
|
+
template: Record<string, any>,
|
|
388
|
+
level = 0
|
|
389
|
+
) => {
|
|
390
|
+
// If it doesn't have a "template strcuture"
|
|
391
|
+
if (!template || typeof template !== "object") return;
|
|
392
|
+
|
|
393
|
+
// For each prop in the "template"
|
|
394
|
+
for (const key in template) {
|
|
395
|
+
const currentComponent = template[key];
|
|
396
|
+
const isValidComponent =
|
|
397
|
+
currentComponent || typeof currentComponent === "object";
|
|
398
|
+
const hasGriddoMultiPageProp = JSON.stringify(
|
|
399
|
+
currentComponent
|
|
400
|
+
).includes('"hasGriddoMultiPage":true');
|
|
401
|
+
|
|
402
|
+
if (!isValidComponent) continue;
|
|
403
|
+
|
|
404
|
+
if (!hasGriddoMultiPageProp) continue;
|
|
405
|
+
|
|
406
|
+
const { component, hasGriddoMultiPage, elements } = currentComponent;
|
|
407
|
+
|
|
408
|
+
if (component && hasGriddoMultiPage) resolve(elements || []);
|
|
409
|
+
|
|
410
|
+
// Recursive call
|
|
411
|
+
getMultiPageComponent(currentComponent, level + 1);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// resolve promise when...
|
|
415
|
+
if (!level) resolve(null);
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
getMultiPageComponent([page]); // ==> En array para que también revise la propia template como objeto.
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
return multiPageElements as Promise<MultiPageElements>;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// -----------------------------------------------------------------------------
|
|
425
|
+
// Private functions
|
|
426
|
+
// -----------------------------------------------------------------------------
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Get `itemsPerPage` elements from the `items` using as offset `page` number.
|
|
430
|
+
* It's a kind of paginator for an array.
|
|
431
|
+
*
|
|
432
|
+
* @param itemsPerPage The items per page.
|
|
433
|
+
* @param items An array of items, the queriedData.
|
|
434
|
+
* @param page The page to be returned.
|
|
435
|
+
*
|
|
436
|
+
* @example
|
|
437
|
+
* getPage(3, ["a", "b", "c", "d", "e", "f", "g", "h"], 2)
|
|
438
|
+
* // -> ["d", "e", "f"]
|
|
439
|
+
*/
|
|
440
|
+
function getPage(
|
|
441
|
+
itemsPerPage: number,
|
|
442
|
+
items: Array<Fields.QueriedDataItem>,
|
|
443
|
+
page: number
|
|
444
|
+
) {
|
|
445
|
+
return items?.slice(itemsPerPage * (page - 1), itemsPerPage * page);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Takes an array of items and split it grouping in arrays of pages based on `itemsPerPage`.
|
|
450
|
+
*
|
|
451
|
+
* @param itemsPerPage The items per page.
|
|
452
|
+
* @param items An array of items, the queriedData.
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* getPageCluster(3, ["a", "b", "c", "d", "e", "f", "g", "h"])
|
|
456
|
+
* // -> [["a", "b", "c"], ["d", "e", "f"], ["g", "h"]]
|
|
457
|
+
*/
|
|
458
|
+
function getPageCluster(
|
|
459
|
+
itemsPerPage: number,
|
|
460
|
+
items: Array<Fields.QueriedDataItem>
|
|
461
|
+
) {
|
|
462
|
+
const totalPagesCount = Math.ceil(items.length / itemsPerPage) || 1;
|
|
463
|
+
const pageNumbers = Array.from({ length: totalPagesCount }, (_, i) => i + 1);
|
|
464
|
+
|
|
465
|
+
return pageNumbers?.map((pageNumber) =>
|
|
466
|
+
getPage(itemsPerPage, items, pageNumber)
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Takes a template object and split the whole queriedItems into separated queriedItems to use in Griddo static list templates.
|
|
472
|
+
*
|
|
473
|
+
* @param listTemplate A template schema with the distributor data included.
|
|
474
|
+
*/
|
|
475
|
+
function getPaginatedPages(listTemplate: TemplateWithDistributor) {
|
|
476
|
+
const items = listTemplate.queriedItems || [];
|
|
477
|
+
const itemsPerPage =
|
|
478
|
+
listTemplate?.itemsPerPage || DEFAULT_ITEMS_PER_PAGE_FOR_LIST_TEMPLATES;
|
|
479
|
+
const pageClusters = getPageCluster(itemsPerPage, items);
|
|
480
|
+
|
|
481
|
+
return pageClusters;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Adds a number to an URL adding optionally an ending slash.
|
|
486
|
+
*
|
|
487
|
+
* @param url The url.
|
|
488
|
+
* @param pageNumber A number to be added to the url.
|
|
489
|
+
* @param options.addEndingSlash Boolean that indicates if return the final url with an end slash or not.
|
|
490
|
+
*
|
|
491
|
+
* @example
|
|
492
|
+
* addPageNumberToUrl("web.com", 3) // "web.com/3"
|
|
493
|
+
* addPageNumberToUrl("web.com", 3, { addEndingSlash: true }) // "web.com/3/"
|
|
494
|
+
*/
|
|
495
|
+
|
|
496
|
+
function addPageNumberToUrl(
|
|
497
|
+
url: string,
|
|
498
|
+
pageNumber: number,
|
|
499
|
+
options?: { addEndingSlash: boolean }
|
|
500
|
+
) {
|
|
501
|
+
const trailingSlash = url.endsWith("/") ? "" : "/";
|
|
502
|
+
const endingSlash = options?.addEndingSlash ? "/" : "";
|
|
503
|
+
|
|
504
|
+
if (pageNumber <= 1) {
|
|
505
|
+
return `${url}${endingSlash}`;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return `${url}${trailingSlash}${pageNumber}${endingSlash}`;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Adds a number to an string with the format "string - number"
|
|
513
|
+
*
|
|
514
|
+
* @param title The title
|
|
515
|
+
* @param pageNumber A number to be added to the title.
|
|
516
|
+
*
|
|
517
|
+
* @example
|
|
518
|
+
* addPageNumberToTitle("The page", 3) // "The page - 3"
|
|
519
|
+
*/
|
|
520
|
+
function addPageNumberToTitle(title: string, pageNumber: number) {
|
|
521
|
+
if (!title || pageNumber <= 1) {
|
|
522
|
+
return title;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
return `${title} - ${pageNumber}`;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export {
|
|
529
|
+
createGriddoListPages,
|
|
530
|
+
createGriddoMultiPages,
|
|
531
|
+
createGriddoSinglePage,
|
|
532
|
+
getMultiPageElements,
|
|
533
|
+
getPaginatedPages,
|
|
534
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Types
|
|
2
|
+
import type { PostSearchInfoProps } from "../types/global";
|
|
3
|
+
|
|
4
|
+
// API
|
|
5
|
+
import { post } from "./api";
|
|
6
|
+
|
|
7
|
+
// Envs
|
|
8
|
+
const API_URL = process.env.API_URL as string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Save in the BBDD the content of a page parsed without HTML tags.
|
|
12
|
+
*
|
|
13
|
+
* @param props Object with parts of the final page object to be saved in the BBDD.
|
|
14
|
+
*/
|
|
15
|
+
async function postSearchInfo(props: PostSearchInfoProps) {
|
|
16
|
+
const {
|
|
17
|
+
title,
|
|
18
|
+
description,
|
|
19
|
+
image,
|
|
20
|
+
pageId,
|
|
21
|
+
languageId,
|
|
22
|
+
siteId,
|
|
23
|
+
url,
|
|
24
|
+
content,
|
|
25
|
+
template,
|
|
26
|
+
} = props;
|
|
27
|
+
|
|
28
|
+
const response = await post({
|
|
29
|
+
endpoint: `${API_URL}/search`,
|
|
30
|
+
body: {
|
|
31
|
+
title,
|
|
32
|
+
description,
|
|
33
|
+
image,
|
|
34
|
+
pageId,
|
|
35
|
+
languageId,
|
|
36
|
+
siteId,
|
|
37
|
+
url,
|
|
38
|
+
template,
|
|
39
|
+
content: prepareHTMLContentForSearch(content),
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return response;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Remove the every cntent inside some HTML tags including them.
|
|
48
|
+
*
|
|
49
|
+
* @param content A string with the content.
|
|
50
|
+
*/
|
|
51
|
+
function prepareHTMLContentForSearch(content: string) {
|
|
52
|
+
const noTagsContent = removeHTMLTags(
|
|
53
|
+
["meta", "link", "style", "script", "noscript", "nav", "header", "footer"],
|
|
54
|
+
content
|
|
55
|
+
);
|
|
56
|
+
const plainTextContent = stripHTMLTags(noTagsContent);
|
|
57
|
+
|
|
58
|
+
return stripSpaces(plainTextContent);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Removes (replacing with empty string) the content for the HTML tags and the tags themself from the content string.
|
|
63
|
+
*
|
|
64
|
+
* @param tags An array of HTML tags without the <>.
|
|
65
|
+
* @param content The content string.
|
|
66
|
+
*/
|
|
67
|
+
function removeHTMLTags(tags: Array<string>, content: string) {
|
|
68
|
+
let filteredContent = content;
|
|
69
|
+
|
|
70
|
+
tags.forEach((tag) => {
|
|
71
|
+
filteredContent = filteredContent
|
|
72
|
+
// eslint-disable-next-line no-useless-escape
|
|
73
|
+
.replace(new RegExp(`<${tag}.*?>.*?<\/${tag}>`, "gis"), " ")
|
|
74
|
+
.replace(new RegExp(`(<${tag}([^>]+)>)`, "gis"), " ");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return filteredContent;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Remove every HTML tags from the content
|
|
82
|
+
*
|
|
83
|
+
* @param content The string to be processed.
|
|
84
|
+
* @param replaceWith The string to replace the remove HTML tags.
|
|
85
|
+
*/
|
|
86
|
+
function stripHTMLTags(content: string) {
|
|
87
|
+
return content.replace(/(<([^>]+)>)/gis, " ");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Removes duplicate whitespaces
|
|
92
|
+
*
|
|
93
|
+
* @param str The string to remove white spaces
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* stripSpaces(" Lorem ipsum dolor ") // " Lorem ipsum dolor "
|
|
97
|
+
*/
|
|
98
|
+
function stripSpaces(str: string) {
|
|
99
|
+
return str.replace(/\s+/g, " ");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { postSearchInfo };
|