PluginProbe
Extendify / 3.1.4
Extendify v3.1.4
3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 0.7.0 All 126 releases
extendify / src / Launch / api / DataApi.js

DataApi.js in Extendify 3.1.4, at src/Launch/api/DataApi.js

470 lines 10.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { AI_HOST, IMAGES_HOST, PATTERNS_HOST } from '@constants';
2 import { getHeadersAndFooters } from '@launch/api/WPApi';
3 import { useUserSelectionStore } from '@launch/state/user-selections';
4 import { formatSiteQuestionsForAPI } from '@shared/utils/format-site-questions-for-api';
5
6 // Optionally add items to request body
7 const allowList = [
8 'partnerId',
9 'devbuild',
10 'version',
11 'siteId',
12 'wpLanguage',
13 'wpVersion',
14 'siteProfile',
15 ];
16
17 const extraBody = {
18 ...Object.fromEntries(
19 Object.entries(window.extSharedData).filter(([key]) =>
20 allowList.includes(key),
21 ),
22 ),
23 };
24
25 const fetchTemplates = async (type, siteType, otherData = {}) => {
26 const { showLocalizedCopy } = window.extSharedData;
27 const otherDataProcessed = Object.entries(otherData).reduce(
28 (acc, [key, value]) => {
29 if (value == null) return acc;
30 acc[key] = typeof value === 'object' ? JSON.stringify(value) : value;
31 return acc;
32 },
33 {},
34 );
35
36 const res = await fetch(`${PATTERNS_HOST}/api/${type}-templates`, {
37 method: 'POST',
38 headers: { 'Content-Type': 'application/json' },
39 body: JSON.stringify({
40 ...extraBody,
41 siteType: siteType?.slug,
42 showLocalizedCopy: !!showLocalizedCopy,
43 ...otherDataProcessed,
44 }),
45 });
46
47 if (!res.ok) throw new Error('Bad response from server');
48
49 return await res.json();
50 };
51
52 export const getHomeTemplates = async ({
53 siteType,
54 siteStructure,
55 siteProfile,
56 siteStrings,
57 siteImages,
58 siteStyles,
59 siteObjective,
60 siteQuestions = [],
61 sitePlugins = [],
62 }) => {
63 const styles = await fetchTemplates('home', siteType, {
64 siteStructure,
65 siteProfile,
66 siteStrings,
67 siteImages,
68 siteStyles,
69 siteObjective,
70 siteQuestions,
71 sitePlugins,
72 });
73 const { wpLanguage, showImprint } = window.extSharedData || {};
74
75 // Check if we should show footer navigation
76 // This is based on the imprint page and the language of the site
77 const hasFooterNav = Array.isArray(showImprint)
78 ? showImprint.includes(wpLanguage ?? '') &&
79 siteProfile?.aiSiteCategory === 'Business'
80 : false;
81
82 const { headers, footers } = await getHeadersAndFooters(hasFooterNav);
83 if (!styles?.length) {
84 throw new Error('Could not get styles');
85 }
86 return styles.map((template, index) => {
87 // Cycle through the headers and footers
88 const header = headers[index % headers.length];
89 const footer = footers[index % footers.length];
90 return {
91 ...template,
92 headerCode: header?.content?.raw?.trim() ?? '',
93 footerCode: footer?.content?.raw?.trim() ?? '',
94 };
95 });
96 };
97
98 export const getPageTemplates = async ({
99 siteType,
100 siteStructure,
101 siteStrings,
102 siteImages,
103 siteStyle,
104 siteQuestions = [],
105 sitePlugins = [],
106 }) => {
107 const { siteInformation, siteProfile } = useUserSelectionStore.getState();
108 const pages = await fetchTemplates('page', siteType, {
109 siteInformation,
110 siteStructure,
111 siteStrings,
112 siteImages,
113 siteStyle,
114 siteProfile,
115 siteQuestions,
116 sitePlugins,
117 });
118 if (!pages?.recommended) {
119 throw new Error('Could not get pages');
120 }
121 return {
122 recommended: pages.recommended.map(({ slug, ...rest }) => ({
123 ...rest,
124 slug,
125 id: slug,
126 })),
127 optional: pages.optional.map(({ slug, ...rest }) => ({
128 ...rest,
129 slug,
130 id: slug,
131 })),
132 };
133 };
134
135 export const generateCustomPatterns = async (page, userState, siteProfile) => {
136 const res = await fetch(`${AI_HOST}/api/patterns`, {
137 method: 'POST',
138 headers: { 'Content-Type': 'application/json' },
139 body: JSON.stringify({
140 ...extraBody,
141 page,
142 userState,
143 siteProfile,
144 }),
145 });
146
147 if (!res.ok) throw new Error('Bad response from server');
148 return await res.json();
149 };
150
151 export const getLinkSuggestions = async (pageContent, availablePages) => {
152 const { siteType } = useUserSelectionStore.getState();
153 try {
154 const res = await fetch(`${AI_HOST}/api/link-pages`, {
155 method: 'POST',
156 headers: { 'Content-Type': 'application/json' },
157 body: JSON.stringify({
158 ...extraBody,
159 siteType: siteType?.slug,
160 pageContent,
161 availablePages,
162 }),
163 });
164 if (!res.ok) throw new Error('Bad response from server');
165 return await res.json();
166 } catch (_error) {
167 // fail gracefully
168 return {};
169 }
170 };
171
172 export const getSiteProfile = async ({ title, description }) => {
173 const url = `${AI_HOST}/api/site-profile`;
174 const method = 'POST';
175 const headers = { 'Content-Type': 'application/json' };
176 const body = JSON.stringify({
177 ...extraBody,
178 title,
179 description,
180 });
181 const fallback = {
182 aiSiteType: null,
183 aiSiteCategory: null,
184 aiDescription: null,
185 aiKeywords: [],
186 logoObjectName: null,
187 };
188 let response;
189 try {
190 response = await fetch(url, { method, headers, body });
191 } catch (_error) {
192 // try one more time
193 try {
194 response = await fetch(url, { method, headers, body });
195 } catch {
196 return fallback;
197 }
198 }
199
200 if (!response?.ok) return fallback;
201
202 try {
203 return (await response.json()) || fallback;
204 } catch (_error) {
205 return fallback;
206 }
207 };
208
209 export const getSiteStrings = async (siteProfile) => {
210 const url = `${AI_HOST}/api/site-strings`;
211 const method = 'POST';
212 const headers = { 'Content-Type': 'application/json' };
213 const body = JSON.stringify({ ...extraBody, siteProfile });
214 const fallback = { aiHeaders: [], aiBlogTitles: [] };
215 let response;
216 try {
217 response = await fetch(url, { method, headers, body });
218 } catch (_error) {
219 // try one more time
220 try {
221 response = await fetch(url, { method, headers, body });
222 } catch {
223 return fallback;
224 }
225 }
226 if (!response?.ok) return fallback;
227 let data;
228 try {
229 data = await response.json();
230 } catch (_error) {
231 return fallback;
232 }
233 return data?.aiHeaders ? data : fallback;
234 };
235
236 export const getSiteImages = async (siteProfile) => {
237 const { aiSiteType, aiSiteCategory, aiDescription, aiKeywords } = siteProfile;
238 const { siteInformation } = useUserSelectionStore.getState();
239 const search = new URLSearchParams({
240 aiSiteType,
241 aiSiteCategory,
242 aiDescription,
243 aiKeywords,
244 ...extraBody,
245 source: 'launch',
246 });
247 if (siteInformation?.title) search.append('title', siteInformation.title);
248 const url = `${IMAGES_HOST}/api/search?${search}`;
249 const method = 'GET';
250 const headers = { 'Content-Type': 'application/json' };
251 const fallback = { siteImages: [] };
252 const requestTimeOut = 10000;
253
254 let response;
255 try {
256 response = await fetch(url, {
257 method,
258 headers,
259 signal: AbortSignal.timeout(requestTimeOut),
260 });
261 } catch (_error) {
262 // try one more time
263 try {
264 response = await fetch(url, {
265 method,
266 headers,
267 signal: AbortSignal.timeout(requestTimeOut),
268 });
269 } catch {
270 return fallback;
271 }
272 }
273
274 if (!response?.ok) return fallback;
275 let data;
276 try {
277 data = await response.json();
278 } catch (_error) {
279 return fallback;
280 }
281 return data?.siteImages ? data : fallback;
282 };
283
284 export const getSiteStyles = async ({ title, siteProfile }) => {
285 const request = new Request(`${AI_HOST}/api/styles`, {
286 method: 'POST',
287 headers: { 'Content-Type': 'application/json' },
288 body: JSON.stringify({ ...extraBody, title, siteProfile }),
289 });
290 const fallback = [];
291
292 let response;
293
294 try {
295 response = await fetch(request);
296 } catch (_error) {
297 // try one more time
298 try {
299 response = await fetch(request);
300 } catch {
301 return fallback;
302 }
303 }
304
305 if (!response?.ok) {
306 return fallback;
307 }
308
309 try {
310 return await response.json();
311 } catch (_) {
312 return fallback;
313 }
314 };
315
316 export const getSiteLogo = async (objectName) => {
317 const url = `${AI_HOST}/api/site-profile/generate-logo`;
318 const method = 'POST';
319 const headers = { 'Content-Type': 'application/json' };
320 const siteId = window.extSharedData?.siteId ?? '';
321 const partnerId = window.extSharedData?.partnerId ?? '';
322 const showAILogo = window.extSharedData?.showAILogo ?? false;
323 const fallback =
324 'https://images.extendify-cdn.com/demo-content/logos/ext-custom-logo-default.webp';
325
326 if (!showAILogo || !objectName) {
327 return fallback;
328 }
329
330 if (!siteId || !partnerId) {
331 throw new Error(
332 'Missing required parameter (siteId, partnerId or objectName)',
333 );
334 }
335
336 const body = JSON.stringify({ objectName, siteId, partnerId });
337
338 let response;
339 try {
340 response = await fetch(url, { method, headers, body });
341 if (!response?.ok) throw new Error('Bad response from server');
342 } catch (_error) {
343 try {
344 response = await fetch(url, { method, headers, body });
345 } catch {
346 return fallback;
347 }
348 }
349
350 if (!response?.ok) return fallback;
351
352 try {
353 const data = await response.json();
354 return data?.logoUrl ?? fallback;
355 } catch (_error) {
356 return fallback;
357 }
358 };
359
360 export const getSiteQuestions = async ({ siteProfile }) => {
361 const url = `${AI_HOST}/api/site-questions`;
362 const method = 'POST';
363 const headers = { 'Content-Type': 'application/json' };
364 const fallback = { questions: [] };
365
366 if (!siteProfile) {
367 return fallback;
368 }
369
370 const { wpLanguage } = window.extSharedData;
371 const { businessInformation, siteObjective } =
372 useUserSelectionStore.getState();
373 const body = JSON.stringify({
374 ...siteProfile,
375 description: businessInformation?.description || '',
376 siteObjective: siteObjective || '',
377 wpLanguage,
378 partnerId: extraBody?.partnerId || null,
379 });
380
381 let response;
382 try {
383 response = await fetch(url, { method, headers, body });
384 if (!response?.ok) throw new Error('Bad response from server');
385 } catch (_error) {
386 try {
387 response = await fetch(url, { method, headers, body });
388 } catch {
389 return fallback;
390 }
391 }
392
393 if (!response?.ok) return fallback;
394
395 try {
396 const data = await response.json();
397 return data?.questions ?? fallback;
398 } catch (_error) {
399 return fallback;
400 }
401 };
402
403 export const getSitePlugins = async ({ siteProfile, siteQA }) => {
404 const url = `${AI_HOST}/api/site-plugins`;
405 const method = 'POST';
406 const headers = { 'Content-Type': 'application/json' };
407 const fallback = [];
408
409 if (!siteProfile) {
410 return fallback;
411 }
412
413 const { wpLanguage, partnerId, pluginGroupId } = window.extSharedData;
414 const { siteObjective } = useUserSelectionStore.getState();
415
416 const body = JSON.stringify({
417 ...siteProfile,
418 siteQuestions: formatSiteQuestionsForAPI(siteQA),
419 siteObjective: siteObjective || '',
420 wpLanguage,
421 partnerId,
422 pluginGroupId,
423 });
424
425 let response;
426
427 try {
428 response = await fetch(url, { method, headers, body });
429 if (!response?.ok) throw new Error('Bad response from server');
430 } catch (_error) {
431 try {
432 response = await fetch(url, { method, headers, body });
433 } catch {
434 return fallback;
435 }
436 }
437
438 if (!response?.ok) return fallback;
439
440 try {
441 const data = await response.json();
442 return data?.selectedPlugins ?? fallback;
443 } catch (_error) {
444 return fallback;
445 }
446 };
447
448 export const getImprintPageTemplate = async (siteStyle = {}) => {
449 const endpoint = `${PATTERNS_HOST}/api/page-imprint`;
450
451 const res = await fetch(endpoint, {
452 method: 'POST',
453 headers: { 'Content-Type': 'application/json' },
454 body: JSON.stringify({
455 ...extraBody,
456 siteStyle: JSON.stringify(siteStyle),
457 }),
458 });
459
460 if (!res.ok) throw new Error('Could not get imprint page');
461
462 const response = await res.json();
463
464 if (!response?.template) {
465 throw new Error('No template found for imprint page');
466 }
467
468 return { ...response.template };
469 };
470