fix: resolve entity logo media URL, robust media upload, and UI media grid icons
This commit is contained in:
parent
84d48ad096
commit
7432e8432b
@ -6,12 +6,11 @@ const nextConfig: NextConfig = {
|
|||||||
outputFileTracingRoot: process.cwd(),
|
outputFileTracingRoot: process.cwd(),
|
||||||
trailingSlash: true,
|
trailingSlash: true,
|
||||||
staticPageGenerationTimeout: 300,
|
staticPageGenerationTimeout: 300,
|
||||||
experimental: {
|
serverActions: {
|
||||||
serverActions: {
|
bodySizeLimit: (process.env.SERVER_ACTIONS_BODY_SIZE_LIMIT as any) || '100mb',
|
||||||
bodySizeLimit: (process.env.SERVER_ACTIONS_BODY_SIZE_LIMIT as any) || '100mb',
|
allowedOrigins: ['almeiraproducciones.com', 'news.almeira.com.co', 'www.almeiraproducciones.com', 'localhost:3000'],
|
||||||
allowedOrigins: ['almeiraproducciones.com', 'news.almeira.com.co', 'www.almeiraproducciones.com', 'localhost:3000'],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
experimental: {},
|
||||||
serverExternalPackages: ['isomorphic-dompurify', 'jsdom'],
|
serverExternalPackages: ['isomorphic-dompurify', 'jsdom'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -121,13 +121,15 @@ export async function uploadMediaDocumentServer(formData: FormData) {
|
|||||||
.trim();
|
.trim();
|
||||||
const smartTitle = cleanName.charAt(0).toUpperCase() + cleanName.slice(1);
|
const smartTitle = cleanName.charAt(0).toUpperCase() + cleanName.slice(1);
|
||||||
|
|
||||||
|
const isImage = file.type ? file.type.startsWith('image/') : /\\.(jpg|jpeg|png|gif|webp|svg)$/i.test(file.name);
|
||||||
|
|
||||||
const doc = await databases.createDocument(DATABASE_ID, 'media', ID.unique(), {
|
const doc = await databases.createDocument(DATABASE_ID, 'media', ID.unique(), {
|
||||||
file_id: uploadedFile.$id,
|
file_id: uploadedFile.$id,
|
||||||
bucket_id: APPWRITE_ALMEIRA_CONFIG.mediaBucketId,
|
bucket_id: APPWRITE_ALMEIRA_CONFIG.mediaBucketId,
|
||||||
titulo: tituloBase || smartTitle || file.name,
|
titulo: tituloBase || smartTitle || file.name,
|
||||||
alt_text: altTextBase || smartTitle || rawName,
|
alt_text: altTextBase || smartTitle || rawName,
|
||||||
descripcion_seo: descSeo,
|
descripcion_seo: descSeo,
|
||||||
tipo: file.type.startsWith('image/') ? 'imagen' : 'video'
|
tipo: isImage ? 'imagen' : 'video'
|
||||||
});
|
});
|
||||||
results.push(doc);
|
results.push(doc);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,21 @@ export async function getEntityConfig() {
|
|||||||
COLLECTION_ID,
|
COLLECTION_ID,
|
||||||
[Query.limit(1)]
|
[Query.limit(1)]
|
||||||
);
|
);
|
||||||
return response.documents[0] ? JSON.parse(JSON.stringify(response.documents[0])) : null;
|
const doc = response.documents[0];
|
||||||
|
if (doc && doc.logotipo && !doc.logotipo.startsWith('http') && !doc.logotipo.startsWith('/')) {
|
||||||
|
try {
|
||||||
|
// Si es un ID de documento de la colección media, lo resolvemos
|
||||||
|
const mediaDoc = await databases.getDocument(DATABASE_ID, 'media', doc.logotipo);
|
||||||
|
if (mediaDoc && mediaDoc.file_id) {
|
||||||
|
const bucketId = mediaDoc.bucket_id || 'media';
|
||||||
|
doc.logotipo = `${ENDPOINT}/storage/buckets/${bucketId}/files/${mediaDoc.file_id}/view?project=${PROJECT_ID}`;
|
||||||
|
}
|
||||||
|
} catch (mediaErr) {
|
||||||
|
// Si falla (por ejemplo, si realmente era un file_id antiguo), no hacemos nada y dejamos que el frontend intente usarlo como file_id
|
||||||
|
console.warn("Could not resolve media doc for logotipo, keeping original value:", mediaErr.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return doc ? JSON.parse(JSON.stringify(doc)) : null;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
// Silently handle 404 (collection not found)
|
// Silently handle 404 (collection not found)
|
||||||
if (error?.code === 404) {
|
if (error?.code === 404) {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { ImageIcon, X, Search, CheckCircle2, UploadCloud, Loader2 } from 'lucide-react';
|
import { ImageIcon, Video, X, Search, CheckCircle2, UploadCloud, Loader2 } from 'lucide-react';
|
||||||
import { databases, APPWRITE_ALMEIRA_CONFIG, endpoint, projectId } from '@/lib/appwrite';
|
import { databases, APPWRITE_ALMEIRA_CONFIG, endpoint, projectId } from '@/lib/appwrite';
|
||||||
import { uploadMediaDocumentServer, listMediaServer, getMediaServer } from '@/app/actions/appwrite';
|
import { uploadMediaDocumentServer, listMediaServer, getMediaServer } from '@/app/actions/appwrite';
|
||||||
|
|
||||||
@ -214,6 +214,9 @@ export const MediaGridSelector = ({
|
|||||||
) : (
|
) : (
|
||||||
<img src={url} alt={item.titulo} title={item.titulo} className="w-full h-full object-cover transition-transform group-hover:scale-110" loading="lazy" />
|
<img src={url} alt={item.titulo} title={item.titulo} className="w-full h-full object-cover transition-transform group-hover:scale-110" loading="lazy" />
|
||||||
)}
|
)}
|
||||||
|
<div className="absolute top-2 left-2 bg-slate-900/80 backdrop-blur-md rounded-lg p-1.5 shadow-lg border border-slate-700/50">
|
||||||
|
{isVideo ? <Video size={14} className="text-cyan-400" /> : <ImageIcon size={14} className="text-pink-400" />}
|
||||||
|
</div>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-cyan-500/20 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none" />
|
<div className="absolute inset-0 bg-gradient-to-t from-cyan-500/20 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none" />
|
||||||
{value === item.$id && (
|
{value === item.$id && (
|
||||||
<div className="absolute top-2 right-2 bg-cyan-500 text-white rounded-full p-1 shadow-lg">
|
<div className="absolute top-2 right-2 bg-cyan-500 text-white rounded-full p-1 shadow-lg">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user