/**
* This component is responsible for rendering a preview of a post inside the Studio.
*/
import { Card, Flex, Spinner, Text } from '@sanity/ui'
import { getSecret } from 'plugins/productionUrl/utils'
import React, {
memo,
startTransition,
Suspense,
useEffect,
useState,
} from 'react'
import { useClient } from 'sanity'
import { suspend } from 'suspend-react'
type Props = {
slug?: string
previewSecretId: `${string}.${string}`
apiVersion: string
}
export default function PostPreviewPane(props: Props) {
const { previewSecretId, apiVersion } = props
// Whenever the slug changes there's it's best to wait a little for elastic search to reach eventual consistency
// this helps prevent seeing "Invalid slug" or 404 errors while editing the slug manually
const [slug, setSlug] = useState(props.slug)
useEffect(() => {
const timeout = setTimeout(
() => startTransition(() => setSlug(props.slug)),
3000
)
return () => clearTimeout(timeout)
}, [props.slug])
// if the document has no slug for the preview iframe
if (!slug) {
return (
Please add a slug to the post to see the preview!
)
}
return (
Loading…
)
}
// Used as a cache key that doesn't risk collision or getting affected by other components that might be using `suspend-react`
const fetchSecret = Symbol('preview.secret')
const Iframe = memo(function Iframe(
props: Omit & Required>
) {
const { apiVersion, previewSecretId, slug } = props
const client = useClient({ apiVersion })
const secret = suspend(
() => getSecret(client, previewSecretId, true),
['getSecret', previewSecretId, fetchSecret],
// The secret fetch has a TTL of 1 minute, just to check if it's necessary to recreate the secret which has a TTL of 60 minutes
{ lifespan: 60000 }
)
const url = new URL('/api/preview', location.origin)
url.searchParams.set('slug', slug)
if (secret) {
url.searchParams.set('secret', secret)
}
return (
)
})