/** * Feed Block - Edit Component * Fetches available feed types from /jvb/v1/feed/types * Allows configuration of content types and inherit query setting */ import { useEffect, useState } from '@wordpress/element'; import { useBlockProps, InspectorControls } from '@wordpress/block-editor'; import { PanelBody, CheckboxControl, ToggleControl, Spinner, Notice } from '@wordpress/components'; import apiFetch from '@wordpress/api-fetch'; import { __ } from '@wordpress/i18n'; export default function Edit({ attributes, setAttributes }) { const [feedTypes, setFeedTypes] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const blockProps = useBlockProps({ className: 'feed-block-editor' }); /** * Fetch available feed types on component mount */ useEffect(() => { apiFetch({ path: '/jvb/v1/feed/types', headers: { 'If-Modified-Since': localStorage.getItem('feed_types_modified'), } }) .then(types => { setFeedTypes(types); setLoading(false); // Store Last-Modified for future requests // (apiFetch doesn't expose response headers easily, // but the server will handle 304s) // Initialize contentTypes if not set and not inheriting if (!attributes.contentTypes && !attributes.inheritQuery) { const firstType = Object.keys(types)[0]; if (firstType) { setAttributes({ contentTypes: [firstType] }); } } }) .catch(err => { console.error('Error loading feed types:', err); setError(err.message); setLoading(false); }); }, [attributes.inheritQuery]); /** * Toggle a content type in the selection */ const toggleContentType = (slug, checked) => { const currentTypes = attributes.contentTypes || []; const newTypes = checked ? [...currentTypes, slug] : currentTypes.filter(t => t !== slug); setAttributes({ contentTypes: newTypes }); }; /** * Get friendly label for content type */ const getTypeLabel = (slug, config) => { return `${config.plural} (${config.type})`; }; /** * Group types by category for better UX */ const groupedTypes = feedTypes ? { content: Object.entries(feedTypes) .filter(([_, config]) => config.type === 'content'), taxonomy: Object.entries(feedTypes) .filter(([_, config]) => config.type === 'taxonomy') } : { content: [], taxonomy: [] }; return (
setAttributes({ inheritQuery: value })} /> {!attributes.inheritQuery && ( <> {loading && (

{__('Loading feed types...', 'jvb')}

)} {error && ( {__('Error loading feed types: ', 'jvb')} {error} )} {!loading && !error && feedTypes && ( <> {groupedTypes.content.length > 0 && ( <>

{__('Content Types', 'jvb')}

{groupedTypes.content.map(([slug, config]) => ( toggleContentType(slug, checked) } help={ config.taxonomies?.length > 0 ? `Filters: ${config.taxonomies.join(', ')}` : null } /> ))} )} {groupedTypes.taxonomy.length > 0 && ( <>

{__('Content Taxonomies', 'jvb')}

{__('These are collections that group other content', 'jvb')}

{groupedTypes.taxonomy.map(([slug, config]) => ( toggleContentType(slug, checked) } help={ config.for_content?.length > 0 ? `Contains: ${config.for_content.join(', ')}` : null } /> ))} )} {!attributes.contentTypes?.length && ( {__('Please select at least one content type', 'jvb')} )} )} )}
setAttributes({ enableGallery: value }) } />

{__('Feed Block', 'jvb')}

{attributes.inheritQuery ? (

{__('📍 Inheriting from page context', 'jvb')}

) : (
{attributes.contentTypes?.length > 0 ? ( <>

{__('Showing:', 'jvb')}

    {attributes.contentTypes.map(type => { const config = feedTypes?.[type]; return (
  • ✓ {config?.plural || type}
  • ); })}
) : (

{__('⚠️ No content types selected', 'jvb')}

)}
)}

{__('Feed will be displayed on the frontend', 'jvb')}

); }