diff --git a/src/app/[slug]/page.tsx b/src/app/[slug]/page.tsx index cbfa012..3350136 100644 --- a/src/app/[slug]/page.tsx +++ b/src/app/[slug]/page.tsx @@ -35,8 +35,9 @@ async function fetchPostData(slugOrId: string) { } } -export default async function NoticiaDetail({ params }: { params: { slug: string } }) { - const post = await fetchPostData(params.slug); +export default async function NoticiaDetail({ params }: { params: Promise<{ slug: string }> }) { + const { slug } = await params; + const post = await fetchPostData(slug); const hasSidebar = await hasSidebarContent(); if (!post) { diff --git a/src/app/clasificados/page.tsx b/src/app/clasificados/page.tsx index 028391b..ef1643a 100644 --- a/src/app/clasificados/page.tsx +++ b/src/app/clasificados/page.tsx @@ -13,10 +13,10 @@ async function fetchClasificadosData() { const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []); const settings: any = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {}; - const postsCount = settings.classifieds_count || 9; + const postsCount = settings.feed_news_count || 12; const cardSettings = { showCategory: settings.news_card_show_category ?? false, - showFooterDate: settings.news_card_show_footer_date ?? true, + showFooterDate: settings.show_news_date ?? false, showFooterButton: settings.news_card_show_footer_button ?? true, footerText: settings.news_card_footer_text || "" }; diff --git a/src/app/dashboard/[entity]/[id]/page.tsx b/src/app/dashboard/[entity]/[id]/page.tsx index 2362030..0ba2f57 100644 --- a/src/app/dashboard/[entity]/[id]/page.tsx +++ b/src/app/dashboard/[entity]/[id]/page.tsx @@ -5,7 +5,7 @@ import Link from 'next/link'; import { updateDocumentServer } from '@/app/actions/appwrite'; import { redirect } from 'next/navigation'; -export default async function EditEntityPage({ params }: { params: { entity: string, id: string } }) { +export default async function EditEntityPage({ params }: { params: Promise<{ entity: string, id: string }> }) { const { entity, id } = await params; const collectionId = collectionMap[entity]; diff --git a/src/app/dashboard/[entity]/new/page.tsx b/src/app/dashboard/[entity]/new/page.tsx index bbd622b..27c0874 100644 --- a/src/app/dashboard/[entity]/new/page.tsx +++ b/src/app/dashboard/[entity]/new/page.tsx @@ -5,7 +5,7 @@ import Link from 'next/link'; import { createDocumentServer } from '@/app/actions/appwrite'; import { redirect } from 'next/navigation'; -export default async function NewEntityPage({ params }: { params: { entity: string } }) { +export default async function NewEntityPage({ params }: { params: Promise<{ entity: string }> }) { const { entity } = await params; const collectionId = collectionMap[entity]; diff --git a/src/app/dashboard/[entity]/page.tsx b/src/app/dashboard/[entity]/page.tsx index 0ca24a6..4ec10a3 100644 --- a/src/app/dashboard/[entity]/page.tsx +++ b/src/app/dashboard/[entity]/page.tsx @@ -11,8 +11,8 @@ export default async function EntityPage({ params, searchParams }: { - params: { entity: string }, - searchParams: { q?: string, page?: string } + params: Promise<{ entity: string }>, + searchParams: Promise<{ q?: string, page?: string }> }) { const { entity } = await params; const sParams = await searchParams; diff --git a/src/app/dashboard/entity/page.tsx b/src/app/dashboard/entity/page.tsx index a633835..3f95670 100644 --- a/src/app/dashboard/entity/page.tsx +++ b/src/app/dashboard/entity/page.tsx @@ -1,13 +1,26 @@ import { getEntity, updateEntity } from '@/app/actions/entity'; -import { Building, Image as ImageIcon, Link as LinkIcon, Share2, Tv, RadioTower } from 'lucide-react'; +import { Building, Image as ImageIcon, Link as LinkIcon, Share2, Tv, RadioTower, Facebook, Instagram, Twitter, Youtube, Send, Mail, Globe, MapPin, Phone, MessageSquare } from 'lucide-react'; +import { createSessionClient } from '@/lib/appwrite.server'; +import { APPWRITE_ALMEIRA_CONFIG } from '@/lib/appwrite'; export default async function EntityPage() { let entity: any = null; + let cities: any[] = []; try { entity = await getEntity(); + + const sessionClient = await createSessionClient(); + if (sessionClient) { + const citiesRes = await sessionClient.databases.listDocuments( + APPWRITE_ALMEIRA_CONFIG.databaseId, + 'cities', + [] + ); + cities = citiesRes.documents; + } } catch (e) { - console.error("No se pudo cargar config de entidad:", e); + console.error("No se pudo cargar la información de la entidad o ciudades:", e); } async function updateEntityClient(formData: FormData) { @@ -17,7 +30,7 @@ export default async function EntityPage() { return (
-
+
@@ -25,7 +38,7 @@ export default async function EntityPage() {

Perfil de Entidad

-

Identidad Corporativa, Contacto y Canales de Streaming

+

Identidad Corporativa, Contacto y Canales

@@ -36,7 +49,7 @@ export default async function EntityPage() {

Identidad Visual

- +
- + {entity?.logotipo && (
Logo actual @@ -57,7 +70,7 @@ export default async function EntityPage() { type="file" name="logotipo" accept="image/*" - className="w-full bg-slate-950/50 border border-slate-800 rounded-xl file:mr-4 file:py-3 file:px-4 file:rounded-l-xl file:border-0 file:text-sm file:font-semibold file:bg-cyan-500/10 file:text-cyan-400 hover:file:bg-cyan-500/20 text-slate-300 text-sm transition-all" + className="w-full bg-slate-950/50 border border-slate-800 rounded-xl file:mr-4 file:py-3 file:px-4 file:rounded-l-xl file:border-0 file:text-[10px] file:font-black file:uppercase file:bg-cyan-500/10 file:text-cyan-400 hover:file:bg-cyan-500/20 text-slate-300 text-sm transition-all" />
@@ -71,36 +84,55 @@ export default async function EntityPage() { {/* Contacto Físico */}
-

Contacto Oficial

+

Contacto Oficial

- - + +
- +
- +
- +
-
-
- - + + {/* Email y Sitio Web en líneas separadas como solicitó el usuario */} +
+ +
+
+ +
+
-
- - +
+
+ +
+
+ +
+
@@ -111,7 +143,7 @@ export default async function EntityPage() {

Canales en Vivo (Streaming)

- + -

Esta URL se usará para el reproductor principal de la sección TV.

- + -

Enlace directo al flujo de audio para la sección Radio.

- {/* Redes Sociales */} + {/* Redes Sociales con Iconos */}

Vínculos Sociales

- +
- +
- +
- +
- +
-
diff --git a/src/app/dashboard/profile/page.tsx b/src/app/dashboard/profile/page.tsx index 8ed3c0c..54e7b5d 100644 --- a/src/app/dashboard/profile/page.tsx +++ b/src/app/dashboard/profile/page.tsx @@ -140,7 +140,7 @@ export default function ProfilePage() { diff --git a/src/app/dashboard/settings/page.tsx b/src/app/dashboard/settings/page.tsx index af3a253..7b1bd42 100644 --- a/src/app/dashboard/settings/page.tsx +++ b/src/app/dashboard/settings/page.tsx @@ -35,15 +35,26 @@ export default async function SettingsPage() { const updateData = { ticker_count: parseInt(formData.get('ticker_count') as string), - rotation_seconds: parseInt(formData.get('rotation_seconds') as string) + feed_news_count: parseInt(formData.get('feed_news_count') as string), + rotation_seconds: parseInt(formData.get('rotation_seconds') as string), + show_news_date: formData.get('show_news_date') === 'true' }; - await sessionClient.databases.updateDocument( - APPWRITE_ALMEIRA_CONFIG.databaseId, - 'settings', - formData.get('docId') as string, - updateData - ); + if (formData.get('docId')) { + await sessionClient.databases.updateDocument( + APPWRITE_ALMEIRA_CONFIG.databaseId, + 'settings', + formData.get('docId') as string, + updateData + ); + } else { + await sessionClient.databases.createDocument( + APPWRITE_ALMEIRA_CONFIG.databaseId, + 'settings', + 'unique()', + updateData + ); + } revalidatePath('/dashboard/settings'); revalidatePath('/'); // Revalidate frontpage @@ -56,7 +67,7 @@ export default async function SettingsPage() { return (
-
+
@@ -75,58 +86,83 @@ export default async function SettingsPage() { {/* Configurador del Ticker */} -
-
- -

Ticker de Noticias

+
+
+ +

Noticias y Feed

-

- Gobierna el cintillo de 'Últimas Noticias' que rota bajo el encabezado superior estableciendo su límite histórico. -

-
- +
+
+ + +
+
+ + +
+
+ +
+
{/* Configurador de Rotación (Banners) */} -
-
- -

Velocidad Carrusel

+
+
+ +

Visualización

-

- Regula el tiempo en pantalla antes de que cambie la lámina (Afecta Banner Principal y Sliders Patrocinados). -

- + - Segundos + Segundos
+ +

+ Estas configuraciones afectan el comportamiento dinámico del sitio web principal y los tiempos de carga de recursos del lado del servidor. +

-
diff --git a/src/app/eventos/page.tsx b/src/app/eventos/page.tsx index cfdb563..a90b74d 100644 --- a/src/app/eventos/page.tsx +++ b/src/app/eventos/page.tsx @@ -13,10 +13,10 @@ async function fetchEventosData() { const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []); const settings: any = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {}; - const postsCount = settings.events_count || 9; + const postsCount = settings.feed_news_count || 12; const cardSettings = { showCategory: settings.news_card_show_category ?? false, - showFooterDate: settings.news_card_show_footer_date ?? true, + showFooterDate: settings.show_news_date ?? false, showFooterButton: settings.news_card_show_footer_button ?? true, footerText: settings.news_card_footer_text || "" }; diff --git a/src/app/globals.css b/src/app/globals.css index 0356e93..a448ab5 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -86,14 +86,17 @@ /* Scrollbar futurista */ ::-webkit-scrollbar { width: 8px; + height: 8px; } ::-webkit-scrollbar-track { background: #020617; } ::-webkit-scrollbar-thumb { - background: #1e293b; - border-radius: 4px; + background: #06b6d4; /* Cyan */ + background: linear-gradient(180deg, #06b6d4 0%, #3b82f6 100%); + border-radius: 10px; + border: 2px solid #020617; } ::-webkit-scrollbar-thumb:hover { - background: #334155; + background: #22d3ee; } diff --git a/src/app/page.tsx b/src/app/page.tsx index e71ee47..8e0401b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -13,10 +13,10 @@ async function fetchHomeData() { const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []); const settings: any = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {}; - const postsCount = settings.feed_count || settings.post_count || 9; + const postsCount = settings.feed_news_count || 12; const cardSettings = { showCategory: settings.news_card_show_category ?? false, - showFooterDate: settings.news_card_show_footer_date ?? true, + showFooterDate: settings.show_news_date ?? false, showFooterButton: settings.news_card_show_footer_button ?? true, footerText: settings.news_card_footer_text || "" }; diff --git a/src/components/NewsTicker.tsx b/src/components/NewsTicker.tsx index bc8ec5f..d321dcb 100644 --- a/src/components/NewsTicker.tsx +++ b/src/components/NewsTicker.tsx @@ -42,16 +42,16 @@ export default async function NewsTicker() { ]); // Resolve Media - const mediaIds = postsRes.documents.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string'); + const mediaIds = postsRes.documents.map((p: any) => p.imagen_destacada_id).filter((id: any) => 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)); + mediaRes.documents.forEach((m: any) => mediaMap.set(m.$id, m)); } - newsItems = postsRes.documents.map(post => { + newsItems = postsRes.documents.map((post: any) => { const media = mediaMap.get(post.imagen_destacada_id); let imagenUrl = post.og_image_url || null; if (media) { @@ -92,7 +92,7 @@ export default async function NewsTicker() { > {noticia.imagenUrl && ( // eslint-disable-next-line @next/next/no-img-element - {noticia.titulo} + {noticia.titulo} )} {!noticia.imagenUrl && } diff --git a/src/components/ProgrammingSchedule.tsx b/src/components/ProgrammingSchedule.tsx index 05ca03b..e9d0bec 100644 --- a/src/components/ProgrammingSchedule.tsx +++ b/src/components/ProgrammingSchedule.tsx @@ -4,15 +4,16 @@ import { useEffect, useState, useRef } from 'react'; export default function ProgrammingSchedule({ matrixData }: { matrixData: Record }) { const [currentTime, setCurrentTime] = useState(new Date()); + const [viewMode, setViewMode] = useState<'day' | 'week'>('day'); const containerRef = useRef(null); useEffect(() => { - // Actualizar cada minuto + // Actualizar cada minuto cada que cambie la hora const interval = setInterval(() => setCurrentTime(new Date()), 60000); return () => clearInterval(interval); }, []); - const days = [ + const allDays = [ { key: 'mon', label: 'Lunes', index: 1 }, { key: 'tue', label: 'Martes', index: 2 }, { key: 'wed', label: 'Miércoles', index: 3 }, @@ -22,20 +23,26 @@ export default function ProgrammingSchedule({ matrixData }: { matrixData: Record { key: 'sun', label: 'Domingo', index: 0 } ]; + const currentDayIndex = currentTime.getDay(); + + // Si estamos en modo día, solo filtramos el día actual + const days = viewMode === 'day' + ? allDays.filter(d => d.index === currentDayIndex) + : allDays; + const slots = Array.from({length: 48}).map((_, i) => { const h = Math.floor(i/2).toString().padStart(2, '0'); const m = i % 2 === 0 ? '00' : '30'; return `${h}:${m}`; }); - const currentDayIndex = currentTime.getDay(); const currentHour = currentTime.getHours(); const currentMinute = currentTime.getMinutes(); const currentSlotIndex = currentHour * 2 + (currentMinute >= 30 ? 1 : 0); // Calc rowSpans to unify cells visually const spans: Record = {}; - days.forEach(d => { + allDays.forEach(d => { const list = slots.map(time => matrixData[`${time}_${d.key}`] || ''); const spanList = new Array(48).fill(1); for(let i=0; i<48; i++){ @@ -58,30 +65,46 @@ export default function ProgrammingSchedule({ matrixData }: { matrixData: Record const scrollAmnt = Math.max(0, (currentSlotIndex - 3) * rowHeight); containerRef.current.scrollTop = scrollAmnt; } - }, [currentSlotIndex]); + }, [currentSlotIndex, viewMode]); return ( -
-
+
+

Parrilla de Programación

+ + {/* Switch Futurista Día / Semana */} +
+ + +
- +
- {days.map(d => { const isToday = d.index === currentDayIndex; return ( - ) })} @@ -95,7 +118,7 @@ export default function ProgrammingSchedule({ matrixData }: { matrixData: Record return ( - {/* Indicador de Línea de Tiempo Rojo (Midiéndose internamente en sus 30 mins) */} + {/* Indicador de Línea de Tiempo Roja */} {isCurrentSlot && (
- Hora + + Hora + {d.label} - {isToday &&
HOY
} + {isToday && viewMode === 'week' &&
HOY
}