diff --git a/almeira-live b/almeira-live index 07ecfa5..4ea666b 160000 --- a/almeira-live +++ b/almeira-live @@ -1 +1 @@ -Subproject commit 07ecfa5268f8b17294a25d08ed82340479f4aaae +Subproject commit 4ea666b69d9f37cb0589be5659572a7ea6440bd0 diff --git a/publish-dummies.js b/publish-dummies.js new file mode 100644 index 0000000..bee04be --- /dev/null +++ b/publish-dummies.js @@ -0,0 +1,78 @@ +const sdk = require('node-appwrite'); +require('dotenv').config({ path: '.env.local' }); + +const client = new sdk.Client(); +const databases = new sdk.Databases(client); + +const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1'; +const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c'; +const API_KEY = process.env.APPWRITE_API_KEY; + +client + .setEndpoint(ENDPOINT) + .setProject(PROJECT_ID) + .setKey(API_KEY); + +const dbId = process.env.APPWRITE_DATABASE_ID || 'almeira'; + +async function publishDummies() { + try { + console.log('Obteniendo tipos de publicación...'); + const typesRes = await databases.listDocuments(dbId, 'publication_types'); + const types = typesRes.documents; + + const typeClasif = types.find(t => t.codigo === 'CLASIFICADO'); + const typeEvento = types.find(t => t.codigo === 'EVENTO'); + const typeBanner = types.find(t => t.codigo === 'DISPLAY_BANNER'); + + if (!typeClasif || !typeEvento || !typeBanner) { + console.log('Faltan algunos tipos de publicación en la base de datos.'); + return; + } + + console.log('Insertando Clasificado de prueba...'); + await databases.createDocument(dbId, 'posts', sdk.ID.unique(), { + titulo: 'Vendo Hermosa Casa en el Centro', + slug: 'vendo-hermosa-casa-centro-' + Date.now(), + resumen_redes: 'Oportunidad única para adquirir una casa con excelentes acabados y ubicación estratégica.', + contenido: '

Oportunidad única para adquirir una casa con excelentes acabados y ubicación estratégica. 3 habitaciones, 2 baños, garaje.

', + estado: 'Publicado', + fecha_publicacion: new Date().toISOString(), + tipo_publicacion_id: typeClasif.$id, + og_image_url: 'https://images.unsplash.com/photo-1512917774080-9991f1c4c750?q=80&w=1000&auto=format&fit=crop' + }); + + console.log('Insertando Evento de prueba...'); + await databases.createDocument(dbId, 'posts', sdk.ID.unique(), { + titulo: 'Gran Concierto de Fin de Año', + slug: 'gran-concierto-fin-de-ano-' + Date.now(), + resumen_redes: 'No te pierdas el evento musical más esperado del año con artistas locales e internacionales.', + contenido: '

No te pierdas el evento musical más esperado del año con artistas locales e internacionales. Entrada libre.

', + estado: 'Publicado', + fecha_publicacion: new Date().toISOString(), + fecha_finalizacion: new Date(Date.now() + 86400000 * 30).toISOString(), // + 30 days + tipo_publicacion_id: typeEvento.$id, + og_image_url: 'https://images.unsplash.com/photo-1540039155733-d76e6148e18e?q=80&w=1000&auto=format&fit=crop' + }); + + console.log('Insertando Banner de prueba...'); + await databases.createDocument(dbId, 'posts', sdk.ID.unique(), { + titulo: 'Gran Promoción Almeira', + slug: 'banner-promo-almeira-' + Date.now(), + contenido: '', // Requerido por el schema de posts + estado: 'Publicado', + fecha_publicacion: new Date().toISOString(), + fecha_finalizacion: new Date(Date.now() + 86400000 * 30).toISOString(), + tipo_publicacion_id: typeBanner.$id, + url_destino: 'https://almeira.com.co', + og_image_url: 'https://images.unsplash.com/photo-1504222490345-c075b6008014?q=80&w=1000&auto=format&fit=crop' + }); + + console.log('¡Publicaciones de prueba insertadas con éxito!'); + + } catch (e) { + console.error('Error insertando dummies:', e); + } +} + +publishDummies(); diff --git a/src/app/clasificados/page.tsx b/src/app/clasificados/page.tsx index 395992b..1307aad 100644 --- a/src/app/clasificados/page.tsx +++ b/src/app/clasificados/page.tsx @@ -1,5 +1,5 @@ import { APPWRITE_ALMEIRA_CONFIG } from '@/lib/appwrite'; -import { createAdminClient } from '@/lib/appwrite.server'; +import { createAdminClient, getLoggedInUser } from '@/lib/appwrite.server'; import { Query } from 'node-appwrite'; import { NewsCard } from '@/components/NewsCard'; import { GlobalSidebar, hasSidebarContent } from '@/components/AdWrappers'; @@ -40,11 +40,16 @@ async function fetchClasificadosData() { if (!typeId) return { posts: [], cardSettings }; const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [ Query.equal('tipo_publicacion_id', typeId), - Query.equal('estado', 'Publicado'), + Query.equal('estado', ['Publicado', 'publicado']), Query.orderDesc('fecha_publicacion'), - Query.limit(postsCount) + Query.limit(postsCount * 2) ]); - posts = postsRes.documents as unknown as Post[]; + + const now = new Date(); + posts = postsRes.documents.filter((post: any) => { + if (!post.fecha_finalizacion) return true; + return new Date(post.fecha_finalizacion) >= now; + }).slice(0, postsCount) as unknown as Post[]; // 3. Resolve Media const mediaIds = posts.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string') as string[]; @@ -73,6 +78,9 @@ export default async function ClasificadosPage() { const { posts, cardSettings } = await fetchClasificadosData(); const hasSidebar = await hasSidebarContent(); + const user = await getLoggedInUser(); + const isAdmin = (user as any)?.labels?.includes('admin') || (user as any)?.labels?.includes('editor') || user?.$id === 'admin-emergency'; + return (
{/* Sci-Fi Hero Section */} @@ -127,9 +135,11 @@ export default async function ClasificadosPage() { 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'; let imagenUrl = post.og_image_url || null; + + const mediaObj = post.resolved_media || (typeof post.imagen_destacada_id === 'object' ? post.imagen_destacada_id : null) as MediaItem | null; - 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`; + if (mediaObj) { + imagenUrl = `${ENDPOINT}/storage/buckets/${mediaObj.bucket_id}/files/${mediaObj.file_id}/preview?project=${PROJECT_ID}&width=800&height=800&quality=85`; } return ( @@ -146,6 +156,8 @@ export default async function ClasificadosPage() { showFooterDate={cardSettings.showFooterDate} showFooterButton={cardSettings.showFooterButton} footerText={cardSettings.footerText} + imageAspect="aspect-square" + isAdmin={isAdmin} /> ) })} diff --git a/src/app/eventos/page.tsx b/src/app/eventos/page.tsx index 91887e6..8221fc9 100644 --- a/src/app/eventos/page.tsx +++ b/src/app/eventos/page.tsx @@ -1,5 +1,5 @@ import { APPWRITE_ALMEIRA_CONFIG } from '@/lib/appwrite'; -import { createAdminClient } from '@/lib/appwrite.server'; +import { createAdminClient, getLoggedInUser } from '@/lib/appwrite.server'; import { Query } from 'node-appwrite'; import { NewsCard } from '@/components/NewsCard'; import { GlobalSidebar, hasSidebarContent } from '@/components/AdWrappers'; @@ -40,11 +40,16 @@ async function fetchEventosData() { if (!typeId) return { posts: [], cardSettings }; const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [ Query.equal('tipo_publicacion_id', typeId), - Query.equal('estado', 'Publicado'), + Query.equal('estado', ['Publicado', 'publicado']), Query.orderDesc('fecha_publicacion'), - Query.limit(postsCount) + Query.limit(postsCount * 2) ]); - posts = postsRes.documents as unknown as Post[]; + + const now = new Date(); + posts = postsRes.documents.filter((post: any) => { + if (!post.fecha_finalizacion) return true; + return new Date(post.fecha_finalizacion) >= now; + }).slice(0, postsCount) as unknown as Post[]; // 3. Resolve Media const mediaIds = posts.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string') as string[]; @@ -73,6 +78,9 @@ export default async function EventosPage() { const { posts, cardSettings } = await fetchEventosData(); const hasSidebar = await hasSidebarContent(); + const user = await getLoggedInUser(); + const isAdmin = (user as any)?.labels?.includes('admin') || (user as any)?.labels?.includes('editor') || user?.$id === 'admin-emergency'; + return (
{/* Sci-Fi Hero Section */} @@ -127,9 +135,11 @@ export default async function EventosPage() { 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'; let imagenUrl = post.og_image_url || null; + + const mediaObj = post.resolved_media || (typeof post.imagen_destacada_id === 'object' ? post.imagen_destacada_id : null) as MediaItem | null; - 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`; + if (mediaObj) { + imagenUrl = `${ENDPOINT}/storage/buckets/${mediaObj.bucket_id}/files/${mediaObj.file_id}/preview?project=${PROJECT_ID}&width=800&height=800&quality=85`; } return ( @@ -146,6 +156,8 @@ export default async function EventosPage() { showFooterDate={cardSettings.showFooterDate} showFooterButton={cardSettings.showFooterButton} footerText={cardSettings.footerText} + imageAspect="aspect-square" + isAdmin={isAdmin} /> ) })} diff --git a/src/app/page.tsx b/src/app/page.tsx index 1e2b6ea..10a5e3c 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -53,7 +53,7 @@ async function fetchHomeData(page: number = 1, isAdmin: boolean = false, adminMo ]; if (isAdmin) { - queries.push(Query.equal('estado', ['Publicado', 'borrador'])); + queries.push(Query.equal('estado', ['Publicado', 'publicado', 'borrador'])); if (adminMonth) { const currentYear = new Date().getFullYear(); // First day of the selected month @@ -64,7 +64,7 @@ async function fetchHomeData(page: number = 1, isAdmin: boolean = false, adminMo queries.push(Query.lessThan('fecha_publicacion', endDate)); } } else { - queries.push(Query.equal('estado', 'Publicado')); + queries.push(Query.equal('estado', ['Publicado', 'publicado'])); } const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', queries); @@ -216,8 +216,10 @@ export default async function Home(props: { searchParams: Promise<{ [key: string const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1'; let imagenUrl = post.og_image_url || null; - 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`; + const mediaObj = post.resolved_media || (typeof post.imagen_destacada_id === 'object' ? post.imagen_destacada_id : null) as MediaItem | null; + + if (mediaObj) { + imagenUrl = `${ENDPOINT}/storage/buckets/${mediaObj.bucket_id}/files/${mediaObj.file_id}/preview?project=${PROJECT_ID}&width=800&height=500&quality=85`; } return ( diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts index 9723374..d125019 100644 --- a/src/app/sitemap.ts +++ b/src/app/sitemap.ts @@ -22,7 +22,7 @@ export default async function sitemap(): Promise { // Fetch all published posts const postsRes = await client.databases.listDocuments(dbId, 'posts', [ - Query.equal('estado', 'Publicado'), + Query.equal('estado', ['Publicado', 'publicado']), Query.limit(1000), // Get up to 1000 posts. For more, pagination is needed. Query.orderDesc('fecha_publicacion') ]); diff --git a/src/components/AdWrappers.tsx b/src/components/AdWrappers.tsx index 411ccd0..d966be4 100644 --- a/src/components/AdWrappers.tsx +++ b/src/components/AdWrappers.tsx @@ -33,7 +33,7 @@ export async function GlobalTopBanner() { const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [ Query.equal('tipo_publicacion_id', typeId), - Query.equal('estado', 'Publicado'), + Query.equal('estado', ['Publicado', 'publicado']), Query.orderDesc('fecha_publicacion'), Query.limit(20) ]); @@ -82,7 +82,7 @@ export async function GlobalSidebar() { if (validTypeIds.length > 0) { const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [ - Query.equal('estado', 'Publicado'), + Query.equal('estado', ['Publicado', 'publicado']), Query.orderAsc('fecha_finalizacion'), Query.limit(50) ]); @@ -135,7 +135,7 @@ export async function hasSidebarContent(): Promise { if (validTypeIds.length === 0) return false; const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [ - Query.equal('estado', 'Publicado'), + Query.equal('estado', ['Publicado', 'publicado']), Query.limit(20) ]); diff --git a/src/components/NewsCard.tsx b/src/components/NewsCard.tsx index 5e367db..4a10937 100644 --- a/src/components/NewsCard.tsx +++ b/src/components/NewsCard.tsx @@ -15,6 +15,7 @@ interface NewsCardProps { showFooterButton?: boolean; footerText?: string; isAdmin?: boolean; + imageAspect?: string; } export const NewsCard = ({ @@ -29,7 +30,8 @@ export const NewsCard = ({ showFooterDate = false, showFooterButton = false, footerText, - isAdmin = false + isAdmin = false, + imageAspect = 'aspect-[16/10]' }: NewsCardProps) => { const titulo = decodeHtmlEntities(rawTitulo); const resumen = decodeHtmlEntities(rawResumen); @@ -59,7 +61,7 @@ export const NewsCard = ({ )} {/* Imagen Destacada */} -
+
{imagenUrl ? ( {titulo} diff --git a/src/components/NewsTicker.tsx b/src/components/NewsTicker.tsx index 5c94225..2d80f03 100644 --- a/src/components/NewsTicker.tsx +++ b/src/components/NewsTicker.tsx @@ -41,7 +41,7 @@ export default async function NewsTicker() { if (!typeId) throw new Error("Could not find typeId for NOTICIA"); const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [ Query.equal('tipo_publicacion_id', typeId), - Query.equal('estado', 'Publicado'), + Query.equal('estado', ['Publicado', 'publicado']), Query.orderDesc('fecha_publicacion'), Query.limit(tickerCount) ]); @@ -57,7 +57,7 @@ export default async function NewsTicker() { } postsRes.documents.forEach((post: any) => { - const media = mediaMap.get(post.imagen_destacada_id); + const media = typeof post.imagen_destacada_id === 'object' ? post.imagen_destacada_id : mediaMap.get(post.imagen_destacada_id); let imagenUrl = post.og_image_url || null; if (media) { imagenUrl = `${APPWRITE_ALMEIRA_CONFIG.endpoint}/storage/buckets/${media.bucket_id}/files/${media.file_id}/preview?project=${APPWRITE_ALMEIRA_CONFIG.projectId}`; diff --git a/src/components/TopBanner.tsx b/src/components/TopBanner.tsx index 2b0a2a8..a4963bd 100644 --- a/src/components/TopBanner.tsx +++ b/src/components/TopBanner.tsx @@ -22,7 +22,7 @@ export default function TopBanner({ initialBanners, rotationSeconds }: { initial const activeBanner = initialBanners[currentIndex]; - if (!activeBanner.imagen_destacada_id) return null; + if (!activeBanner.imagen_destacada_id && !activeBanner.og_image_url) return null; const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'https://appwrite.almeira.com.co/v1'; const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69b84df5003bd8957c5c';