| 1 |
import { getImagesShape } from '@auto-launch/fetchers/shape'; |
| 2 |
import { collectBuiltPageImageUrls } from '@auto-launch/functions/get-imported-images'; |
| 3 |
import { |
| 4 |
failWithFallback, |
| 5 |
fetchWithTimeout, |
| 6 |
retryTwice, |
| 7 |
setStatus, |
| 8 |
} from '@auto-launch/functions/helpers'; |
| 9 |
import { launchStrings } from '@auto-launch/strings'; |
| 10 |
import { IMAGES_HOST } from '@constants'; |
| 11 |
import { reqDataBasics } from '@shared/lib/data'; |
| 12 |
|
| 13 |
const fallback = { siteImages: { hero: [], general: [] } }; |
| 14 |
const url = `${IMAGES_HOST}/api/images`; |
| 15 |
const { wpLanguage } = window.extSharedData; |
| 16 |
const method = 'POST'; |
| 17 |
const headers = { 'Content-Type': 'application/json' }; |
| 18 |
// A shipped build can never change a count it sends; the service can. |
| 19 |
const imageTypes = [{ type: 'hero' }, { type: 'general' }]; |
| 20 |
const MIN_POOL_SIZE = 10; |
| 21 |
|
| 22 |
const asImages = (urls) => urls.map((link) => ({ url: link })); |
| 23 |
// The build's reusable images exclude its hero, so they are section photos. |
| 24 |
const asSections = (urls) => ({ hero: [], general: asImages(urls) }); |
| 25 |
|
| 26 |
export const handleSiteImages = async ({ siteProfile, designBuild }) => { |
| 27 |
// translators: this is for a action log UI. Keep it short |
| 28 |
setStatus(launchStrings().statusImages); |
| 29 |
|
| 30 |
// Reuse the design preview's own images; only search for what is missing. |
| 31 |
const seeded = collectBuiltPageImageUrls(designBuild?.builtPages); |
| 32 |
if (seeded.length >= MIN_POOL_SIZE) return { siteImages: asSections(seeded) }; |
| 33 |
|
| 34 |
const body = JSON.stringify({ |
| 35 |
...reqDataBasics, |
| 36 |
siteProfile, |
| 37 |
lang: wpLanguage, |
| 38 |
imageTypes, |
| 39 |
source: 'auto-launch', |
| 40 |
}); |
| 41 |
|
| 42 |
const response = await retryTwice(() => |
| 43 |
fetchWithTimeout(url, { method, headers, body }), |
| 44 |
); |
| 45 |
|
| 46 |
if (!response?.ok) return { siteImages: asSections(seeded) }; |
| 47 |
|
| 48 |
const { siteImages: found } = await failWithFallback( |
| 49 |
async () => { |
| 50 |
const { images } = await response.json(); |
| 51 |
return getImagesShape.parse({ siteImages: images }); |
| 52 |
}, |
| 53 |
fallback, |
| 54 |
{ caller: 'handleSiteImages' }, |
| 55 |
); |
| 56 |
|
| 57 |
if (!seeded.length) return { siteImages: found }; |
| 58 |
|
| 59 |
const seededSet = new Set(seeded); |
| 60 |
const topup = found.general |
| 61 |
.filter((image) => !seededSet.has(image.url)) |
| 62 |
.slice(0, MIN_POOL_SIZE - seeded.length); |
| 63 |
return { |
| 64 |
siteImages: { hero: found.hero, general: [...asImages(seeded), ...topup] }, |
| 65 |
}; |
| 66 |
}; |
| 67 |
|