Fix: Featured images resolution, NewsCard redesign, and settings configurability

This commit is contained in:
Carlos (Almeira) 2026-03-26 14:47:02 -05:00
parent 43dd3770b9
commit a446a70854
6 changed files with 196 additions and 63 deletions

View File

@ -2,15 +2,22 @@ import { APPWRITE_ALMEIRA_CONFIG } from '@/lib/appwrite';
import { createAdminClient } from '@/lib/appwrite.server'; import { createAdminClient } from '@/lib/appwrite.server';
import { Query } from 'node-appwrite'; import { Query } from 'node-appwrite';
import { NewsCard } from '@/components/NewsCard'; import { NewsCard } from '@/components/NewsCard';
import { Loader2, Sparkles } from 'lucide-react'; import { Sparkles } from 'lucide-react';
async function fetchClasificadosData() { async function fetchClasificadosData() {
try { try {
const client = await createAdminClient(); const client = await createAdminClient();
// 1. Settings for count // 1. Settings
const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []); const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []);
const postsCount = settingsRes.documents.length > 0 ? (settingsRes.documents[0].classifieds_count || 9) : 9; const settings = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {};
const postsCount = settings.classifieds_count || 9;
const cardSettings = {
showCategory: settings.news_card_show_category ?? false,
showFooterDate: settings.news_card_show_footer_date ?? true,
footerText: settings.news_card_footer_text || ""
};
// 2. Get CLASIFICADO type ID // 2. Get CLASIFICADO type ID
const typeRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'publication_types', [ const typeRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'publication_types', [
@ -27,17 +34,27 @@ async function fetchClasificadosData() {
Query.limit(postsCount) Query.limit(postsCount)
]); ]);
posts = postsRes.documents; posts = postsRes.documents;
// 3. Resolve Media
const mediaIds = posts.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string');
if (mediaIds.length > 0) {
const mediaRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'media', [
Query.equal('$id', mediaIds)
]);
const mediaMap = new Map(mediaRes.documents.map(m => [m.$id, m]));
posts = posts.map(p => ({ ...p, resolved_media: mediaMap.get(p.imagen_destacada_id) }));
}
} }
return { posts }; return { posts, cardSettings };
} catch (e) { } catch (e) {
console.error("Clasificados fetch error", e); console.error("Clasificados fetch error", e);
return { posts: [] }; return { posts: [], cardSettings: { showCategory: false, showFooterDate: true, footerText: "" } };
} }
} }
export default async function ClasificadosPage() { export default async function ClasificadosPage() {
const { posts } = await fetchClasificadosData(); const { posts, cardSettings } = await fetchClasificadosData();
return ( return (
<main className="animate-fade-in relative min-h-screen"> <main className="animate-fade-in relative min-h-screen">
@ -90,9 +107,10 @@ export default async function ClasificadosPage() {
{posts.map((post) => { {posts.map((post) => {
const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c'; const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c';
const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1'; const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1';
let imagenUrl = null; let imagenUrl = post.og_image_url || null;
if (post.imagen_destacada_id) {
imagenUrl = `${ENDPOINT}/storage/buckets/${post.imagen_destacada_id.bucket_id}/files/${post.imagen_destacada_id.file_id}/preview?project=${PROJECT_ID}&width=800&height=500&quality=85`; if (post.resolved_media) {
imagenUrl = `${ENDPOINT}/storage/buckets/${post.resolved_media.bucket_id}/files/${post.resolved_media.file_id}/preview?project=${PROJECT_ID}&width=800&height=500&quality=85`;
} }
return ( return (
@ -101,10 +119,13 @@ export default async function ClasificadosPage() {
id={post.$id} id={post.$id}
slug={post.slug || post.$id} slug={post.slug || post.$id}
titulo={post.titulo} titulo={post.titulo}
resumen={post.resumen_redes || post.contenido?.substring(0, 100).replace(/<[^>]*>?/gm, '') + '...'} resumen={post.resumen_redes || post.contenido?.replace(/<[^>]*>?/gm, '').substring(0, 150) + '...'}
tipo="Aviso" tipo="Aviso"
fecha={post.fecha_publicacion || post.$createdAt} fecha={post.fecha_publicacion || post.$createdAt}
imagenUrl={imagenUrl} imagenUrl={imagenUrl}
showCategory={cardSettings.showCategory}
showFooterDate={cardSettings.showFooterDate}
footerText={cardSettings.footerText}
/> />
) )
})} })}

View File

@ -2,15 +2,22 @@ import { APPWRITE_ALMEIRA_CONFIG } from '@/lib/appwrite';
import { createAdminClient } from '@/lib/appwrite.server'; import { createAdminClient } from '@/lib/appwrite.server';
import { Query } from 'node-appwrite'; import { Query } from 'node-appwrite';
import { NewsCard } from '@/components/NewsCard'; import { NewsCard } from '@/components/NewsCard';
import { Loader2, Calendar } from 'lucide-react'; import { Calendar } from 'lucide-react';
async function fetchEventosData() { async function fetchEventosData() {
try { try {
const client = await createAdminClient(); const client = await createAdminClient();
// 1. Settings for count // 1. Settings
const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []); const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []);
const postsCount = settingsRes.documents.length > 0 ? (settingsRes.documents[0].events_count || 9) : 9; const settings = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {};
const postsCount = settings.events_count || 9;
const cardSettings = {
showCategory: settings.news_card_show_category ?? false,
showFooterDate: settings.news_card_show_footer_date ?? true,
footerText: settings.news_card_footer_text || ""
};
// 2. Get EVENTO type ID // 2. Get EVENTO type ID
const typeRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'publication_types', [ const typeRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'publication_types', [
@ -27,17 +34,27 @@ async function fetchEventosData() {
Query.limit(postsCount) Query.limit(postsCount)
]); ]);
posts = postsRes.documents; posts = postsRes.documents;
// 3. Resolve Media
const mediaIds = posts.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string');
if (mediaIds.length > 0) {
const mediaRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'media', [
Query.equal('$id', mediaIds)
]);
const mediaMap = new Map(mediaRes.documents.map(m => [m.$id, m]));
posts = posts.map(p => ({ ...p, resolved_media: mediaMap.get(p.imagen_destacada_id) }));
}
} }
return { posts }; return { posts, cardSettings };
} catch (e) { } catch (e) {
console.error("Eventos fetch error", e); console.error("Eventos fetch error", e);
return { posts: [] }; return { posts: [], cardSettings: { showCategory: false, showFooterDate: true, footerText: "" } };
} }
} }
export default async function EventosPage() { export default async function EventosPage() {
const { posts } = await fetchEventosData(); const { posts, cardSettings } = await fetchEventosData();
return ( return (
<main className="animate-fade-in relative min-h-screen"> <main className="animate-fade-in relative min-h-screen">
@ -90,9 +107,10 @@ export default async function EventosPage() {
{posts.map((post) => { {posts.map((post) => {
const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c'; const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c';
const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1'; const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1';
let imagenUrl = null; let imagenUrl = post.og_image_url || null;
if (post.imagen_destacada_id) {
imagenUrl = `${ENDPOINT}/storage/buckets/${post.imagen_destacada_id.bucket_id}/files/${post.imagen_destacada_id.file_id}/preview?project=${PROJECT_ID}&width=800&height=500&quality=85`; if (post.resolved_media) {
imagenUrl = `${ENDPOINT}/storage/buckets/${post.resolved_media.bucket_id}/files/${post.resolved_media.file_id}/preview?project=${PROJECT_ID}&width=800&height=500&quality=85`;
} }
return ( return (
@ -101,10 +119,13 @@ export default async function EventosPage() {
id={post.$id} id={post.$id}
slug={post.slug || post.$id} slug={post.slug || post.$id}
titulo={post.titulo} titulo={post.titulo}
resumen={post.resumen_redes || post.contenido?.substring(0, 100).replace(/<[^>]*>?/gm, '') + '...'} resumen={post.resumen_redes || post.contenido?.replace(/<[^>]*>?/gm, '').substring(0, 150) + '...'}
tipo="Evento" tipo="Evento"
fecha={post.fecha_publicacion || post.$createdAt} fecha={post.fecha_publicacion || post.$createdAt}
imagenUrl={imagenUrl} imagenUrl={imagenUrl}
showCategory={cardSettings.showCategory}
showFooterDate={cardSettings.showFooterDate}
footerText={cardSettings.footerText}
/> />
) )
})} })}

View File

@ -37,9 +37,17 @@ export default async function NoticiaDetail({ params }: { params: { slug: string
const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c'; const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c';
const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1'; const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1';
let imagenUrl = null; let imagenUrl = post.og_image_url || null;
if (post.imagen_destacada_id) { if (post.imagen_destacada_id) {
imagenUrl = `${ENDPOINT}/storage/buckets/${post.imagen_destacada_id.bucket_id}/files/${post.imagen_destacada_id.file_id}/preview?project=${PROJECT_ID}&width=1200&height=600&quality=90`; // En vista de detalle, resolvemos el documento de media
try {
const client = await createAdminClient();
const mediaRes = await client.databases.getDocument(APPWRITE_ALMEIRA_CONFIG.databaseId, 'media', post.imagen_destacada_id);
if (mediaRes) {
imagenUrl = `${ENDPOINT}/storage/buckets/${mediaRes.bucket_id}/files/${mediaRes.file_id}/preview?project=${PROJECT_ID}&width=1200&height=600&quality=90`;
}
} catch(e) {}
} }
const fechaObj = new Date(post.fecha_publicacion || post.$createdAt); const fechaObj = new Date(post.fecha_publicacion || post.$createdAt);

View File

@ -3,16 +3,22 @@ import { createAdminClient } from '@/lib/appwrite.server';
import { Query } from 'node-appwrite'; import { Query } from 'node-appwrite';
import { NewsCard } from '@/components/NewsCard'; import { NewsCard } from '@/components/NewsCard';
import { GlobalSidebar } from '@/components/AdWrappers'; import { GlobalSidebar } from '@/components/AdWrappers';
import { RadioTower, Sparkles, ChevronDown, Loader2 } from 'lucide-react'; import { RadioTower, Sparkles, ChevronDown } from 'lucide-react';
import { Suspense } from 'react';
async function fetchHomeData() { async function fetchHomeData() {
try { try {
const client = await createAdminClient(); const client = await createAdminClient();
// 1. Settings for count // 1. Settings
const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []); const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []);
const postsCount = settingsRes.documents.length > 0 ? (settingsRes.documents[0].feed_count || settingsRes.documents[0].post_count || 9) : 9; const settings = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {};
const postsCount = settings.feed_count || settings.post_count || 9;
const cardSettings = {
showCategory: settings.news_card_show_category ?? false,
showFooterDate: settings.news_card_show_footer_date ?? true,
footerText: settings.news_card_footer_text || ""
};
// 2. Get NOTICIA type ID // 2. Get NOTICIA type ID
const typeRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'publication_types', [ const typeRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'publication_types', [
@ -29,17 +35,31 @@ async function fetchHomeData() {
Query.limit(postsCount) Query.limit(postsCount)
]); ]);
posts = postsRes.documents; posts = postsRes.documents;
// 3. Resolve Media documents for images
const mediaIds = posts.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string');
if (mediaIds.length > 0) {
const mediaRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'media', [
Query.equal('$id', mediaIds)
]);
const mediaMap = new Map(mediaRes.documents.map(m => [m.$id, m]));
posts = posts.map(p => ({
...p,
resolved_media: mediaMap.get(p.imagen_destacada_id)
}));
}
} }
return { posts }; return { posts, cardSettings };
} catch (e) { } catch (e) {
console.error("Home fetch error", e); console.error("Home fetch error", e);
return { posts: [] }; return { posts: [], cardSettings: { showCategory: false, showFooterDate: true, footerText: "" } };
} }
} }
export default async function Home() { export default async function Home() {
const { posts } = await fetchHomeData(); const { posts, cardSettings } = await fetchHomeData();
return ( return (
<main className="animate-fade-in relative"> <main className="animate-fade-in relative">
@ -110,9 +130,10 @@ export default async function Home() {
{posts.map((post) => { {posts.map((post) => {
const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c'; const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c';
const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1'; const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1';
let imagenUrl = null; let imagenUrl = post.og_image_url || null;
if (post.imagen_destacada_id) {
imagenUrl = `${ENDPOINT}/storage/buckets/${post.imagen_destacada_id.bucket_id}/files/${post.imagen_destacada_id.file_id}/preview?project=${PROJECT_ID}&width=800&height=500&quality=85`; if (post.resolved_media) {
imagenUrl = `${ENDPOINT}/storage/buckets/${post.resolved_media.bucket_id}/files/${post.resolved_media.file_id}/preview?project=${PROJECT_ID}&width=800&height=500&quality=85`;
} }
return ( return (
@ -121,10 +142,13 @@ export default async function Home() {
id={post.$id} id={post.$id}
slug={post.slug || post.$id} slug={post.slug || post.$id}
titulo={post.titulo} titulo={post.titulo}
resumen={post.resumen_redes || post.contenido?.substring(0, 100).replace(/<[^>]*>?/gm, '') + '...'} resumen={post.resumen_redes || post.contenido?.replace(/<[^>]*>?/gm, '').substring(0, 150) + '...'}
tipo="Noticia" tipo="Noticia"
fecha={post.fecha_publicacion || post.$createdAt} fecha={post.fecha_publicacion || post.$createdAt}
imagenUrl={imagenUrl} imagenUrl={imagenUrl}
showCategory={cardSettings.showCategory}
showFooterDate={cardSettings.showFooterDate}
footerText={cardSettings.footerText}
/> />
) )
})} })}

View File

@ -1,7 +1,31 @@
import Link from 'next/link'; import Link from 'next/link';
import { ArrowUpRight, Calendar } from 'lucide-react'; import { ArrowUpRight, Calendar } from 'lucide-react';
export const NewsCard = ({ id, slug, titulo, resumen, tipo, fecha, imagenUrl }: any) => { interface NewsCardProps {
id: string;
slug: string;
titulo: string;
resumen: string;
tipo?: string;
fecha: string;
imagenUrl?: string | null;
showCategory?: boolean;
showFooterDate?: boolean;
footerText?: string;
}
export const NewsCard = ({
id,
slug,
titulo,
resumen,
tipo,
fecha,
imagenUrl,
showCategory = false,
showFooterDate = true,
footerText
}: NewsCardProps) => {
// Formatear fecha // Formatear fecha
const fechaObj = new Date(fecha); const fechaObj = new Date(fecha);
const fechaFormateada = fechaObj.toLocaleDateString('es-ES', { day: '2-digit', month: 'short', year: 'numeric' }); const fechaFormateada = fechaObj.toLocaleDateString('es-ES', { day: '2-digit', month: 'short', year: 'numeric' });
@ -14,22 +38,24 @@ export const NewsCard = ({ id, slug, titulo, resumen, tipo, fecha, imagenUrl }:
{imagenUrl ? ( {imagenUrl ? (
<img src={imagenUrl} alt={titulo} className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110" /> <img src={imagenUrl} alt={titulo} className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110" />
) : ( ) : (
<div className="w-full h-full flex items-center justify-center text-slate-600 font-bold uppercase tracking-widest text-sm bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-slate-800 to-slate-900"> <div className="w-full h-full flex items-center justify-center bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-slate-800 to-slate-900">
Almeira Media {/* No placeholder text as per user request */}
</div> </div>
)} )}
{/* Badge/Tag */} {/* Badge/Tag - Habilitable por prop */}
{showCategory && (
<div className="absolute top-4 left-4 z-20"> <div className="absolute top-4 left-4 z-20">
<span className="px-3 py-1.5 rounded-full text-xs font-bold uppercase tracking-wider backdrop-blur-md border border-white/20 bg-black/40 text-cyan-300 shadow-[0_0_10px_rgba(6,182,212,0.2)]"> <span className="px-3 py-1.5 rounded-full text-xs font-bold uppercase tracking-wider backdrop-blur-md border border-white/20 bg-black/40 text-cyan-300 shadow-[0_0_10px_rgba(6,182,212,0.2)]">
{tipo?.toUpperCase() || 'NOTICIA'} {tipo?.toUpperCase() || 'NOTICIA'}
</span> </span>
</div> </div>
)}
</div> </div>
{/* Contenido */} {/* Contenido */}
<div className="flex flex-col flex-grow p-6 relative z-20"> <div className="flex flex-col flex-grow p-6 relative z-20">
<div className="flex items-center gap-2 text-cyan-500/80 text-xs font-bold tracking-widest uppercase mb-4"> <div className="flex items-center gap-2 text-cyan-500/80 text-sm font-bold tracking-widest uppercase mb-4">
<Calendar size={14} /> <Calendar size={14} />
<span>{fechaFormateada}</span> <span>{fechaFormateada}</span>
</div> </div>
@ -45,7 +71,14 @@ export const NewsCard = ({ id, slug, titulo, resumen, tipo, fecha, imagenUrl }:
{/* Footer del card */} {/* Footer del card */}
<div className="mt-auto pt-5 border-t border-white/10 flex items-center justify-between"> <div className="mt-auto pt-5 border-t border-white/10 flex items-center justify-between">
<span className="text-xs font-black tracking-widest uppercase text-cyan-500 group-hover:text-cyan-300 transition-colors"> <span className="text-xs font-black tracking-widest uppercase text-cyan-500 group-hover:text-cyan-300 transition-colors">
Expandir Registro {showFooterDate ? (
<div className="flex items-center gap-2">
<Calendar size={12} />
{fechaFormateada}
</div>
) : (
footerText || "Ver más"
)}
</span> </span>
<div className="w-8 h-8 rounded-full bg-white/5 flex items-center justify-center border border-white/10 group-hover:bg-cyan-500 group-hover:border-cyan-400 group-hover:text-slate-950 transition-all"> <div className="w-8 h-8 rounded-full bg-white/5 flex items-center justify-center border border-white/10 group-hover:bg-cyan-500 group-hover:border-cyan-400 group-hover:text-slate-950 transition-all">
<ArrowUpRight size={16} className="transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5" /> <ArrowUpRight size={16} className="transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5" />

View File

@ -20,26 +20,52 @@ export default async function NewsTicker() {
// Since 'createSessionClient' uses the session cookie, we might have issues on public incognito pages. // Since 'createSessionClient' uses the session cookie, we might have issues on public incognito pages.
// The user previously used Admin API key for everything or a local backdoor. // The user previously used Admin API key for everything or a local backdoor.
// Settings // Settings const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []);
const settingsRes = await sessionClient.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []); const settings: any = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {};
const tickerCount = settingsRes.documents.length > 0 ? settingsRes.documents[0].ticker_count : 10; const tickerCount = settings.ticker_count || 10;
// Get Type ID for "Noticia" // 2. Get NOTICIA type ID
const typeRes = await sessionClient.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'publication_types', [ const typeRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'publication_types', [
Query.equal('codigo', 'NOTICIA') Query.equal('codigo', 'NOTICIA')
]); ]);
let newsItems: any[] = [];
if (typeRes.documents.length > 0) { if (typeRes.documents.length > 0) {
const typeId = typeRes.documents[0].$id; const typeId = typeRes.documents[0].$id;
const postsRes = await sessionClient.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [ const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [
Query.equal('tipo_publicacion_id', typeId), Query.equal('tipo_publicacion_id', typeId),
Query.equal('estado', 'Publicado'), Query.equal('estado', 'Publicado'),
Query.orderDesc('fecha_publicacion'), Query.orderDesc('fecha_publicacion'),
Query.limit(tickerCount) Query.limit(tickerCount)
]); ]);
noticias = postsRes.documents;
// Resolve Media
const mediaIds = postsRes.documents.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string');
const mediaMap = new Map();
if (mediaIds.length > 0) {
const mediaRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'media', [
Query.equal('$id', mediaIds)
]);
mediaRes.documents.forEach(m => mediaMap.set(m.$id, m));
} }
newsItems = postsRes.documents.map(post => {
const media = mediaMap.get(post.imagen_destacada_id);
let imagenUrl = post.og_image_url || null;
if (media) {
imagenUrl = `${process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1'}/storage/buckets/${media.bucket_id}/files/${media.file_id}/preview?project=${process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c'}`;
}
return {
id: post.$id,
titulo: post.titulo,
slug: post.slug || post.$id,
imagenUrl
};
});
}
noticias = newsItems; // Assign resolved news items to 'noticias'
} catch (e) { } catch (e) {
console.error("Ticker fetch error", e); console.error("Ticker fetch error", e);
} }