diff --git a/config/admin.ts b/config/admin.ts index 5476b6f..a10f301 100644 --- a/config/admin.ts +++ b/config/admin.ts @@ -1,24 +1,128 @@ -import type { Core } from '@strapi/strapi'; +import type { Core, UID } from "@strapi/strapi"; -const config = ({ env }: Core.Config.Shared.ConfigParams): Core.Config.Admin => ({ - auth: { - secret: env('ADMIN_JWT_SECRET'), - }, - apiToken: { - salt: env('API_TOKEN_SALT'), - }, - transfer: { - token: { - salt: env('TRANSFER_TOKEN_SALT'), +/** + * Generate preview pathname based on content type and document + * @param {string} uid - Content type identifier (e.g., 'api::article.article') + * @param {object} options - Options containing locale and document data + * @returns {string|null} - The preview pathname or null if no preview available + */ +const getPreviewPathname = (uid, { locale, document }) => { + const { slug } = document || {}; + + switch (uid) { + // Global single type - preview on homepage + case "api::global.global": + return "/"; + + // Generic pages with slugs + case "api::page.page": + if (!slug) { + return null; // No slug, no preview + } + return `/${slug}`; + + // Articles/blog posts + case "api::article.article": + if (!slug) { + return "/articles"; // Could redirect to articles index + } + return `/articles/${slug}`; + + // Products (example) + case "api::product.product": + if (!slug) { + return "/products"; + } + return `/products/${slug}`; + + // Add more content types as needed + default: + // Return null for content types that shouldn't have previews + // (e.g., configuration, metadata, components) + return null; + } +}; + +const config = ({ + env, +}: Core.Config.Shared.ConfigParams): Core.Config.Admin => { + const clientUrl = env("CLIENT_URL"); + const previewSecret = env("PREVIEW_SECRET"); + + return { + auth: { + secret: env("ADMIN_JWT_SECRET"), }, - }, - secrets: { - encryptionKey: env('ENCRYPTION_KEY'), - }, - flags: { - nps: env.bool('FLAG_NPS', true), - promoteEE: env.bool('FLAG_PROMOTE_EE', true), - }, -}); + apiToken: { + salt: env("API_TOKEN_SALT"), + }, + transfer: { + token: { + salt: env("TRANSFER_TOKEN_SALT"), + }, + }, + secrets: { + encryptionKey: env("ENCRYPTION_KEY"), + }, + flags: { + nps: env.bool("FLAG_NPS", true), + promoteEE: env.bool("FLAG_PROMOTE_EE", true), + }, + // Preview + preview: { + enabled: true, + config: { + // Allow preview iframe to load from your frontend domain + allowedOrigins: [clientUrl], + + /** + * Preview handler - generates preview URLs for content + * @param {string} uid - Content type UID + * @param {object} context - Preview context + * @param {string} context.documentId - Document ID being previewed + * @param {string} context.locale - Document locale + * @param {string} context.status - Document status ('draft' or 'published') + * @returns {string|null} - Preview URL or null to disable preview + */ + async handler(uid, { documentId, locale, status }) { + try { + // Fetch the complete document from Strapi + const document = await strapi + .documents(uid as UID.ContentType) + .findOne({ + documentId, + // Ensure we get the correct version based on status + ...(status === "draft" && { status: "draft" }), + }); + + // Generate the preview pathname + const pathname = getPreviewPathname(uid, { locale, document }); + + // If no pathname is generated, disable preview for this content type + if (!pathname) { + return null; + } + + // Build preview URL with all necessary parameters + const urlSearchParams = new URLSearchParams({ + path: pathname, + secret: previewSecret, + status: status || "draft", + documentId, + uid, + ...(locale && { locale }), + }); + + // Return the complete preview URL pointing to your Vike app's preview API + return `${clientUrl}/api/preview?${urlSearchParams}`; + } catch (error) { + console.error("Preview handler error:", error); + return null; + } + }, + }, + }, + }; +}; export default config;