From 4892a3d79833ecff68d8af82a8c56d8f2fcd8d43 Mon Sep 17 00:00:00 2001 From: "Carlos (Almeira)" Date: Sun, 29 Mar 2026 22:27:07 -0500 Subject: [PATCH] fix: media library pagination, preview URLs and dashboard layout optimization --- src/app/actions/appwrite.ts | 8 +-- src/app/dashboard/[entity]/page.tsx | 1 + .../dashboard/MediaGridSelector.tsx | 34 +++++++++-- src/components/media/StreamOverlays.tsx | 56 +++++++++++++------ .../publications/PublicationLayout.tsx | 3 - .../publications/PublicationsList.tsx | 2 +- src/lib/appwrite.ts | 1 + 7 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/app/actions/appwrite.ts b/src/app/actions/appwrite.ts index 86f50c1..b4f8651 100644 --- a/src/app/actions/appwrite.ts +++ b/src/app/actions/appwrite.ts @@ -1,7 +1,7 @@ 'use server' import { Client, Databases, Storage, ID } from 'node-appwrite'; -import { databaseId } from '@/lib/appwrite'; +import { APPWRITE_ALMEIRA_CONFIG, databaseId } from '@/lib/appwrite'; import { revalidatePath } from 'next/cache'; import { InputFile } from 'node-appwrite/file'; @@ -75,7 +75,7 @@ export async function uploadMediaServer(formData: FormData) { for (const file of files) { const buffer = Buffer.from(await file.arrayBuffer()); const inputFile = InputFile.fromBuffer(buffer, file.name); - const result = await storage.createFile('media', ID.unique(), inputFile); + const result = await storage.createFile(APPWRITE_ALMEIRA_CONFIG.mediaBucketId, ID.unique(), inputFile); results.push(result); } @@ -102,11 +102,11 @@ export async function uploadMediaDocumentServer(formData: FormData) { for (const file of files) { const buffer = Buffer.from(await file.arrayBuffer()); const inputFile = InputFile.fromBuffer(buffer, file.name); - const uploadedFile = await storage.createFile('media', ID.unique(), inputFile); + const uploadedFile = await storage.createFile(APPWRITE_ALMEIRA_CONFIG.mediaBucketId, ID.unique(), inputFile); const doc = await databases.createDocument(DATABASE_ID, 'media', ID.unique(), { file_id: uploadedFile.$id, - bucket_id: 'media', + bucket_id: APPWRITE_ALMEIRA_CONFIG.mediaBucketId, titulo: file.name, alt_text: file.name.split('.')[0], tipo: file.type.startsWith('image/') ? 'imagen' : 'video' diff --git a/src/app/dashboard/[entity]/page.tsx b/src/app/dashboard/[entity]/page.tsx index 04d110a..fb21396 100644 --- a/src/app/dashboard/[entity]/page.tsx +++ b/src/app/dashboard/[entity]/page.tsx @@ -144,6 +144,7 @@ export default async function EntityPage({ {entity === 'posts' ? ( (null); @@ -46,13 +47,23 @@ export const MediaGridSelector = ({ if (isOpen) fetchMedia(); }, [isOpen]); - const fetchMedia = async () => { + const fetchMedia = async (more = false) => { setIsLoading(true); try { + const currentOffset = more ? mediaItems.length : 0; const res = await databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'media', [ - Query.limit(100), Query.orderDesc('$createdAt') + Query.limit(20), + Query.offset(currentOffset), + Query.orderDesc('$createdAt') ]); - setMediaItems(res.documents); + + if (more) { + setMediaItems(prev => [...prev, ...res.documents]); + } else { + setMediaItems(res.documents); + } + + setHasMore(res.documents.length === 20); } catch (error) { console.error('Error fetching media:', error); } finally { @@ -200,8 +211,19 @@ export const MediaGridSelector = ({ )} -
- {filteredItems.length} Archivos Disponibles +
+ {mediaItems.length} Archivos Disponibles + + {hasMore && ( + + )}
diff --git a/src/components/media/StreamOverlays.tsx b/src/components/media/StreamOverlays.tsx index 51cc8e7..705244b 100644 --- a/src/components/media/StreamOverlays.tsx +++ b/src/components/media/StreamOverlays.tsx @@ -13,11 +13,21 @@ export const StreamOverlays = () => { // 1. Fetch Approved Messages for Ticker const fetchApprovedMessages = async () => { try { - const res = await databases.listDocuments( - APPWRITE_ALMEIRA_CONFIG.databaseId, - 'whatsapp_messages', - [Query.equal('status', 'approved'), Query.limit(10), Query.orderDesc('timestamp')] - ); + let res; + try { + res = await databases.listDocuments( + APPWRITE_ALMEIRA_CONFIG.databaseId, + 'whatsapp_messages', + [Query.equal('status', 'approved'), Query.limit(10), Query.orderDesc('timestamp')] + ); + } catch (queryError) { + // Fallback for missing 'status' attribute + res = await databases.listDocuments( + APPWRITE_ALMEIRA_CONFIG.databaseId, + 'whatsapp_messages', + [Query.limit(10), Query.orderDesc('$createdAt')] + ); + } setApprovedMessages(res.documents); } catch (error) { console.error('Error fetching approved messages:', error); @@ -51,12 +61,13 @@ export const StreamOverlays = () => { if (response.events.includes('databases.*.collections.*.documents.*.update') || response.events.includes('databases.*.collections.*.documents.*.create')) { const payload = response.payload as any; - if (payload.status === 'approved') { + // Only process as approved if the status exists, otherwise treat all as approved for the ticker if schema is simple + if (payload.status === 'approved' || !payload.hasOwnProperty('status')) { setApprovedMessages(prev => { const filtered = prev.filter(m => m.$id !== payload.$id); return [payload, ...filtered].slice(0, 10); }); - } else { + } else if (payload.status && payload.status !== 'approved') { setApprovedMessages(prev => prev.filter(m => m.$id !== payload.$id)); } } @@ -121,17 +132,26 @@ export const StreamOverlays = () => { {activeItem && (
- {activeItem.imagen_destacada_id ? ( - {activeItem.titulo} - ) : ( -
- -
- )} + {(() => { + const mediaId = typeof activeItem.imagen_destacada_id === 'object' + ? activeItem.imagen_destacada_id?.$id + : activeItem.imagen_destacada_id; + + if (mediaId) { + return ( + {activeItem.titulo} + ); + } + return ( +
+ +
+ ); + })()}

{activeItem.titulo} diff --git a/src/components/publications/PublicationLayout.tsx b/src/components/publications/PublicationLayout.tsx index 0e3e1ee..d0e58a8 100644 --- a/src/components/publications/PublicationLayout.tsx +++ b/src/components/publications/PublicationLayout.tsx @@ -202,9 +202,6 @@ export const PublicationLayout: React.FC = ({

{initialData?.$id ? 'Editar Publicación' : 'Nueva Publicación'}

-

- {initialData?.$id ? `ID: ${initialData.$id}` : 'Completa todos los campos requeridos.'} -

diff --git a/src/components/publications/PublicationsList.tsx b/src/components/publications/PublicationsList.tsx index df0198e..b14aeaf 100644 --- a/src/components/publications/PublicationsList.tsx +++ b/src/components/publications/PublicationsList.tsx @@ -246,7 +246,7 @@ export const PublicationsList: React.FC = ({ )} {filteredAndSortedPosts.length > 0 ? ( -
+
{filteredAndSortedPosts.map((post) => (