From 235ce5716edc2f7cbe80fdccf26eac7269587839 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 08 Jun 2026 04:38:18 +0000
Subject: [PATCH] =FavouritesManager.php and FavouritesRoutes.php fixes. Moving all logic to FavouritesManager.php. Still some left to do
---
src/feed/edit.js | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 256 insertions(+), 0 deletions(-)
diff --git a/src/feed/edit.js b/src/feed/edit.js
new file mode 100644
index 0000000..2a5228d
--- /dev/null
+++ b/src/feed/edit.js
@@ -0,0 +1,256 @@
+/**
+ * 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 (
+ <div {...blockProps}>
+ <InspectorControls>
+ <PanelBody
+ title={__('Feed Settings', 'jvb')}
+ initialOpen={true}
+ >
+ <ToggleControl
+ label={__('Inherit from Page Context', 'jvb')}
+ help={
+ attributes.inheritQuery
+ ? __('Feed will adapt to the current page (profile, taxonomy, etc.)', 'jvb')
+ : __('Manually select content types to display', 'jvb')
+ }
+ checked={attributes.inheritQuery}
+ onChange={(value) => setAttributes({ inheritQuery: value })}
+ />
+
+ {!attributes.inheritQuery && (
+ <>
+ {loading && (
+ <div style={{ textAlign: 'center', padding: '20px' }}>
+ <Spinner />
+ <p>{__('Loading feed types...', 'jvb')}</p>
+ </div>
+ )}
+
+ {error && (
+ <Notice status="error" isDismissible={false}>
+ {__('Error loading feed types: ', 'jvb')} {error}
+ </Notice>
+ )}
+
+ {!loading && !error && feedTypes && (
+ <>
+ {groupedTypes.content.length > 0 && (
+ <>
+ <h4>{__('Content Types', 'jvb')}</h4>
+ {groupedTypes.content.map(([slug, config]) => (
+ <CheckboxControl
+ key={slug}
+ label={getTypeLabel(slug, config)}
+ checked={
+ attributes.contentTypes?.includes(slug) || false
+ }
+ onChange={(checked) =>
+ toggleContentType(slug, checked)
+ }
+ help={
+ config.taxonomies?.length > 0
+ ? `Filters: ${config.taxonomies.join(', ')}`
+ : null
+ }
+ />
+ ))}
+ </>
+ )}
+
+ {groupedTypes.taxonomy.length > 0 && (
+ <>
+ <h4 style={{ marginTop: '20px' }}>
+ {__('Content Taxonomies', 'jvb')}
+ </h4>
+ <p style={{ fontSize: '12px', color: '#757575' }}>
+ {__('These are collections that group other content', 'jvb')}
+ </p>
+ {groupedTypes.taxonomy.map(([slug, config]) => (
+ <CheckboxControl
+ key={slug}
+ label={getTypeLabel(slug, config)}
+ checked={
+ attributes.contentTypes?.includes(slug) || false
+ }
+ onChange={(checked) =>
+ toggleContentType(slug, checked)
+ }
+ help={
+ config.for_content?.length > 0
+ ? `Contains: ${config.for_content.join(', ')}`
+ : null
+ }
+ />
+ ))}
+ </>
+ )}
+
+ {!attributes.contentTypes?.length && (
+ <Notice status="warning" isDismissible={false}>
+ {__('Please select at least one content type', 'jvb')}
+ </Notice>
+ )}
+ </>
+ )}
+ </>
+ )}
+ </PanelBody>
+
+ <PanelBody
+ title={__('Display Settings', 'jvb')}
+ initialOpen={false}
+ >
+ <ToggleControl
+ label={__('Show Gallery View', 'jvb')}
+ help={__('Enable lightbox for images', 'jvb')}
+ checked={attributes.enableGallery || false}
+ onChange={(value) =>
+ setAttributes({ enableGallery: value })
+ }
+ />
+ </PanelBody>
+ </InspectorControls>
+
+ <div className="feed-block-placeholder">
+ <div className="feed-block-icon">
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="none">
+ <rect x="3" y="3" width="7" height="7" fill="currentColor" opacity="0.3" />
+ <rect x="13" y="3" width="7" height="7" fill="currentColor" opacity="0.3" />
+ <rect x="3" y="13" width="7" height="7" fill="currentColor" opacity="0.3" />
+ <rect x="13" y="13" width="7" height="7" fill="currentColor" opacity="0.3" />
+ </svg>
+ </div>
+
+ <h3>{__('Feed Block', 'jvb')}</h3>
+
+ {attributes.inheritQuery ? (
+ <p className="feed-block-description">
+ {__('📍 Inheriting from page context', 'jvb')}
+ </p>
+ ) : (
+ <div className="feed-block-description">
+ {attributes.contentTypes?.length > 0 ? (
+ <>
+ <p><strong>{__('Showing:', 'jvb')}</strong></p>
+ <ul style={{
+ listStyle: 'none',
+ padding: '0',
+ margin: '8px 0'
+ }}>
+ {attributes.contentTypes.map(type => {
+ const config = feedTypes?.[type];
+ return (
+ <li key={type} style={{
+ padding: '4px 0',
+ color: '#2271b1'
+ }}>
+ ✓ {config?.plural || type}
+ </li>
+ );
+ })}
+ </ul>
+ </>
+ ) : (
+ <p style={{ color: '#d63638' }}>
+ {__('⚠️ No content types selected', 'jvb')}
+ </p>
+ )}
+ </div>
+ )}
+
+ <p className="feed-block-note">
+ {__('Feed will be displayed on the frontend', 'jvb')}
+ </p>
+ </div>
+ </div>
+ );
+}
--
Gitblit v1.10.0