From 2b545b28d59f03f12bc994567c5556cc59676c70 Mon Sep 17 00:00:00 2001 From: "Carlos (Almeira)" Date: Mon, 22 Jun 2026 08:58:08 -0500 Subject: [PATCH] chore: format dates globally in datatable and entity form --- package-hostinger.sh | 4 +- src/app/dashboard/[entity]/page.tsx | 18 ++++- src/components/dashboard/DataTable.tsx | 9 +++ src/components/dashboard/EntityForm.tsx | 5 +- src/lib/validators/publications.ts | 2 +- update-multivision-slugs.js | 90 +++++++++++++++++++++++++ 6 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 update-multivision-slugs.js diff --git a/package-hostinger.sh b/package-hostinger.sh index fd77232..114df7a 100755 --- a/package-hostinger.sh +++ b/package-hostinger.sh @@ -42,8 +42,8 @@ fi # 7. Copiar archivo de entorno de ejemplo o variables if [ -f ".env.local" ]; then - echo "Copiando variables locales como plantilla .env.production.example..." - cp .env.local "$DEPLOY_DIR/.env.production.example" + echo "Copiando variables locales a .env.production..." + cp .env.local "$DEPLOY_DIR/.env.production" fi # 7.5. Modificar package.json para evitar que Hostinger intente hacer build diff --git a/src/app/dashboard/[entity]/page.tsx b/src/app/dashboard/[entity]/page.tsx index 571a438..831e7b1 100644 --- a/src/app/dashboard/[entity]/page.tsx +++ b/src/app/dashboard/[entity]/page.tsx @@ -82,8 +82,7 @@ export default async function EntityPage({ documents = JSON.parse(JSON.stringify(response.documents)); total = response.total; - if (entity === 'posts') { - const fields = SCHEMA_MAP[entity] || []; + const fields = SCHEMA_MAP[entity] || []; await Promise.all( fields .filter((f) => f.type === 'relation' && f.relationCollection) @@ -113,7 +112,20 @@ export default async function EntityPage({ } catch { } }) ); - } + + // Enrich documents with resolved relation data for DataTable + documents = documents.map(doc => { + const enriched = { ...doc }; + fields.forEach(field => { + if (field.type === 'relation' && typeof enriched[field.name] === 'string' && relationData[field.name]) { + const relDoc = relationData[field.name].find(r => r.$id === enriched[field.name]); + if (relDoc) { + enriched[field.name] = relDoc; + } + } + }); + return enriched; + }); } catch (error) { console.error(`Error fetching entity ${entity}:`, error); } diff --git a/src/components/dashboard/DataTable.tsx b/src/components/dashboard/DataTable.tsx index eef26a0..afa5664 100644 --- a/src/components/dashboard/DataTable.tsx +++ b/src/components/dashboard/DataTable.tsx @@ -145,6 +145,15 @@ export const DataTable = ({ value = Array.isArray(value) ? `[Lista (${value.length})]` : value.$id || '[Vinculado]'; } } + + if (field.type === 'date' && value) { + try { + value = new Intl.DateTimeFormat('es-CO', { + year: 'numeric', month: 'short', day: '2-digit', + hour: '2-digit', minute: '2-digit' + }).format(new Date(value as string)); + } catch(e) {} + } if (typeof value === 'boolean') { value = value ? 'Sí' : 'No'; diff --git a/src/components/dashboard/EntityForm.tsx b/src/components/dashboard/EntityForm.tsx index 1c6e299..b8c564e 100644 --- a/src/components/dashboard/EntityForm.tsx +++ b/src/components/dashboard/EntityForm.tsx @@ -148,7 +148,10 @@ export const EntityForm = ({ if (val === undefined || val === null) return ''; if (field.type === 'boolean') return val ? 'true' : 'false'; - if (field.type === 'date') return new Date(val).toISOString().slice(0, 16); + if (field.type === 'date') { + if (!val) return ''; + try { return new Date(val).toISOString().slice(0, 16); } catch(e) { return ''; } + } if (field.type === 'relation') return typeof val === 'object' ? val.$id : val; return val; }; diff --git a/src/lib/validators/publications.ts b/src/lib/validators/publications.ts index c1dcd02..66f6ad3 100644 --- a/src/lib/validators/publications.ts +++ b/src/lib/validators/publications.ts @@ -36,7 +36,7 @@ export const PostSchema = z.object({ message: 'Estado inválido.', }), - tipo: z.enum(['noticia', 'evento', 'aviso', 'comunicado', 'galeria'], { + tipo: z.enum(['noticia', 'evento', 'aviso', 'clasificado', 'blog'], { message: 'Tipo de contenido inválido.', }), diff --git a/update-multivision-slugs.js b/update-multivision-slugs.js new file mode 100644 index 0000000..57d57d9 --- /dev/null +++ b/update-multivision-slugs.js @@ -0,0 +1,90 @@ +const { Client, Databases, Query } = require('node-appwrite'); +require('dotenv').config({ path: '.env.local' }); + +const client = new Client() + .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT) + .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID) + .setKey(process.env.APPWRITE_API_KEY); + +const databases = new Databases(client); +const DB_ID = process.env.APPWRITE_DATABASE_ID; + +const makeSlug = (text) => { + if (!text) return ''; + return text + .normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/(^-|-$)+/g, ''); +}; + +async function updateSlugs() { + try { + console.log('Connecting to Appwrite to update Multivision slugs...'); + + const collections = await databases.listCollections(DB_ID); + const map = {}; + collections.collections.forEach(c => { map[c.name.toLowerCase()] = c.$id; }); + const postsCollectionId = map['posts'] || 'posts'; + + let cursor = null; + let updatedCount = 0; + let totalCount = 0; + + while (true) { + const queries = [ + Query.startsWith('slug', 'multivision-'), + Query.limit(100) + ]; + + if (cursor) queries.push(Query.cursorAfter(cursor)); + + const res = await databases.listDocuments(DB_ID, postsCollectionId, queries); + + console.log(`Fetched ${res.documents.length} matching documents in this batch.`); + + for (const doc of res.documents) { + totalCount++; + const newSlug = makeSlug(doc.titulo); + console.log(`Updating document ${doc.$id}`); + console.log(` Old slug: ${doc.slug}`); + console.log(` New slug: ${newSlug}`); + + try { + await databases.updateDocument(DB_ID, postsCollectionId, doc.$id, { + slug: newSlug + }); + updatedCount++; + } catch (updateErr) { + console.error(` Failed to update ${doc.$id}: ${updateErr.message}`); + + if (updateErr.message.includes('unique') || updateErr.code === 409) { + const alternativeSlug = `${newSlug}-${Math.floor(Math.random() * 1000)}`; + console.log(` Trying alternative slug: ${alternativeSlug}`); + try { + await databases.updateDocument(DB_ID, postsCollectionId, doc.$id, { + slug: alternativeSlug + }); + updatedCount++; + } catch (e) { + console.error(` Failed alternative update for ${doc.$id}: ${e.message}`); + } + } + } + } + + if (res.documents.length < 100) break; + cursor = res.documents[res.documents.length - 1].$id; + } + + console.log(`\nOperation complete. Found ${totalCount} multivision posts, successfully updated ${updatedCount}.`); + process.exit(0); + + } catch (error) { + console.error('Error:', error); + process.exit(1); + } +} + +updateSlugs();