From ec3bf7cd4c511fd6d68575a32d0112b601efc29a Mon Sep 17 00:00:00 2001 From: Tristan Mouchet Date: Mon, 23 Mar 2026 09:56:05 +0100 Subject: [PATCH] refactor: use file manager for SEO social preview image --- app/ycode/components/PageSettingsPanel.tsx | 204 ++++----------------- 1 file changed, 34 insertions(+), 170 deletions(-) diff --git a/app/ycode/components/PageSettingsPanel.tsx b/app/ycode/components/PageSettingsPanel.tsx index 5c211cce..acb876f5 100644 --- a/app/ycode/components/PageSettingsPanel.tsx +++ b/app/ycode/components/PageSettingsPanel.tsx @@ -42,9 +42,8 @@ import Icon from '@/components/ui/icon'; import { getPageIcon, isHomepage, buildSlugPath, buildFolderPath, folderHasIndexPage, generateUniqueSlug, generateSlug, sanitizeSlug, isReservedRootSlug } from '@/lib/page-utils'; import { isAssetOfType, ASSET_CATEGORIES } from '@/lib/asset-utils'; import { Textarea } from '@/components/ui/textarea'; -import { uploadFileApi, deleteAssetApi } from '@/lib/api'; import { useAsset } from '@/hooks/use-asset'; -import { useAssetsStore } from '@/stores/useAssetsStore'; +import { useEditorStore } from '@/stores/useEditorStore'; import RichTextEditor from './RichTextEditor'; import { Separator } from '@/components/ui/separator'; import { cn } from '@/lib/utils'; @@ -123,9 +122,7 @@ const PageSettingsPanel = React.forwardRef(null); const [seoNoindex, setSeoNoindex] = useState(false); - const [pendingImageFile, setPendingImageFile] = useState(null); - const [imagePreviewUrl, setImagePreviewUrl] = useState(null); - const fileInputRef = useRef(null); + const { openFileManager } = useEditorStore(); const nameInputRef = useRef(null); @@ -145,17 +142,11 @@ const PageSettingsPanel = React.forwardRef(null); - // Only use asset hook if seoImage is a string (asset ID) const seoImageId = typeof seoImage === 'string' ? seoImage : null; const seoImageAsset = useAsset(seoImageId); - const { addAsset, removeAsset } = useAssetsStore(); - const displayAsset = uploadedAssetCache || seoImageAsset; - // Check if there's any image displayed (including temp preview) - const hasImage = seoImage !== null || imagePreviewUrl !== null || displayAsset !== null; - // Check if there's an uploaded asset (not a field variable) - const hasUploadedAsset = (imagePreviewUrl || displayAsset) && !isSeoImageFieldVariable(seoImage); + const hasImage = seoImage !== null || seoImageAsset !== null; + const hasSelectedAsset = seoImageAsset !== null && !isSeoImageFieldVariable(seoImage); const [currentPage, setCurrentPage] = useState(page); @@ -196,12 +187,6 @@ const PageSettingsPanel = React.forwardRef { - if (uploadedAssetCache && seoImageAsset && uploadedAssetCache.id === seoImageAsset.id) { - setUploadedAssetCache(null); - } - }, [uploadedAssetCache, seoImageAsset]); - const [saveCounter, setSaveCounter] = useState(0); const [showUnsavedDialog, setShowUnsavedDialog] = useState(false); const [pendingAction, setPendingAction] = useState<'close' | 'navigate' | 'external' | null>(null); @@ -375,8 +360,7 @@ const PageSettingsPanel = React.forwardRef ({ @@ -498,8 +482,7 @@ const PageSettingsPanel = React.forwardRef { - return () => { - if (imagePreviewUrl) { - URL.revokeObjectURL(imagePreviewUrl); - } - }; - }, [imagePreviewUrl]); - // Auto-generate slug from name for new pages (only if not index or error page) useEffect(() => { if (!currentPage && name && !isIndex && !isErrorPage) { @@ -750,48 +709,25 @@ const PageSettingsPanel = React.forwardRef) => { - const file = event.target.files?.[0]; - if (!file) return; - - if (!isAssetOfType(file.type, ASSET_CATEGORIES.IMAGES)) { - setError('Only image files are allowed'); - return; - } - - const MAX_FILE_SIZE = 10 * 1024 * 1024; - if (file.size > MAX_FILE_SIZE) { - setError('File size must be less than 10MB'); - return; - } - - if (imagePreviewUrl) { - URL.revokeObjectURL(imagePreviewUrl); - } - - const previewUrl = URL.createObjectURL(file); - setImagePreviewUrl(previewUrl); - setPendingImageFile(file); - setError(null); + const handleOpenFileManager = () => { + openFileManager( + (asset) => { + if (!asset.mime_type || !isAssetOfType(asset.mime_type, ASSET_CATEGORIES.IMAGES)) { + return false; + } + setSeoImage(asset.id); + }, + seoImageId, + [ASSET_CATEGORIES.IMAGES] + ); }; const handleRemoveImage = () => { - if (imagePreviewUrl) { - URL.revokeObjectURL(imagePreviewUrl); - setImagePreviewUrl(null); - } - - setPendingImageFile(null); setSeoImage(null); - setUploadedAssetCache(null); - - if (fileInputRef.current) { - fileInputRef.current.value = ''; - } }; // Render Select component for image field variables - const renderImageFieldSelect = (clearAsset: boolean = false) => { + const renderImageFieldSelect = () => { if (!isDynamicPage) return null; const activeCollectionId = collectionId || currentPage?.settings?.cms?.collection_id || ''; @@ -823,29 +759,10 @@ const PageSettingsPanel = React.forwardRef - + {selectedField ? selectedField.name : 'Select field'} @@ -918,13 +835,6 @@ const PageSettingsPanel = React.forwardRefSocial preview Recommended image size is at least 1,200 x 630 pixels.
-
{isSeoImageFieldVariable(seoImage) ? null : (() => { - const imageUrl = imagePreviewUrl || displayAsset?.public_url; + const imageUrl = seoImageAsset?.public_url; return imageUrl ? ( - {hasUploadedAsset ? ( + {hasSelectedAsset ? ( )} - {isDynamicPage && !hasFieldVariable && !hasUploadedAsset && or} + {isDynamicPage && !hasFieldVariable && !hasSelectedAsset && or} - {!hasUploadedAsset && renderImageFieldSelect(hasFieldVariable)} + {!hasSelectedAsset && renderImageFieldSelect()} )} - {(hasUploadedAsset || hasFieldVariable) && ( + {(hasSelectedAsset || hasFieldVariable) && (