73 lines
2.1 KiB
React
73 lines
2.1 KiB
React
import { createContext, useContext, useEffect, useState } from 'react';
|
|
import defaultContent from '../../server/seed/default-content.json';
|
|
|
|
const ContentContext = createContext(null);
|
|
|
|
const API_BASE = import.meta.env.VITE_API_URL || '';
|
|
|
|
export function ContentProvider({ children, previewMode = false }) {
|
|
const [content, setContent] = useState(defaultContent);
|
|
const [loading, setLoading] = useState(!previewMode);
|
|
const [error, setError] = useState(null);
|
|
const [updatedAt, setUpdatedAt] = useState(null);
|
|
|
|
useEffect(() => {
|
|
if (previewMode) return;
|
|
|
|
fetch(`${API_BASE}/api/content`)
|
|
.then((res) => {
|
|
if (!res.ok) throw new Error('Failed to load content');
|
|
return res.json();
|
|
})
|
|
.then((data) => {
|
|
const { _updatedAt, ...rest } = data;
|
|
setContent(rest);
|
|
setUpdatedAt(_updatedAt);
|
|
setError(null);
|
|
})
|
|
.catch((err) => {
|
|
console.warn('Using fallback content:', err.message);
|
|
setError(err.message);
|
|
})
|
|
.finally(() => setLoading(false));
|
|
}, [previewMode]);
|
|
|
|
useEffect(() => {
|
|
if (!previewMode) return;
|
|
|
|
setLoading(false);
|
|
|
|
const onMessage = (event) => {
|
|
if (event.origin !== window.location.origin) return;
|
|
if (event.data?.type !== 'ADMIN_PREVIEW' || !event.data.fullContent) return;
|
|
|
|
setContent(event.data.fullContent);
|
|
setLoading(false);
|
|
|
|
const anchor = event.data.anchor;
|
|
if (!anchor) return;
|
|
|
|
window.setTimeout(() => {
|
|
document.getElementById(anchor)?.scrollIntoView({ behavior: 'auto', block: 'start' });
|
|
}, 180);
|
|
};
|
|
|
|
window.addEventListener('message', onMessage);
|
|
window.parent?.postMessage({ type: 'PREVIEW_READY' }, window.location.origin);
|
|
|
|
return () => window.removeEventListener('message', onMessage);
|
|
}, [previewMode]);
|
|
|
|
return (
|
|
<ContentContext.Provider value={{ content, loading, error, updatedAt, previewMode }}>
|
|
{children}
|
|
</ContentContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useContent() {
|
|
const ctx = useContext(ContentContext);
|
|
if (!ctx) throw new Error('useContent must be used within ContentProvider');
|
|
return ctx;
|
|
}
|