refactor: improve project integrity with shared types and strict Appwrite document casting
- Create shared Settings interface in @/types/settings. - Refactor NewsTicker, AdWrappers, and page components to use shared types. - Remove risky 'as any' casting from Appwrite document resolution. - Update Post interface to include resolved_media for consistent data handling. - Verify Zod error handling consistency across the src directory.
This commit is contained in:
parent
ea551469b7
commit
339ac0125e
@ -4,6 +4,8 @@ import { Query } from 'node-appwrite';
|
||||
import { NewsCard } from '@/components/NewsCard';
|
||||
import { GlobalSidebar, hasSidebarContent } from '@/components/AdWrappers';
|
||||
import { Sparkles } from 'lucide-react';
|
||||
import { Settings } from '@/types/settings';
|
||||
import { Post, MediaItem } from '@/types/publications';
|
||||
|
||||
async function fetchClasificadosData() {
|
||||
try {
|
||||
@ -11,7 +13,7 @@ async function fetchClasificadosData() {
|
||||
|
||||
// 1. Settings
|
||||
const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []);
|
||||
const settings: any = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {};
|
||||
const settings = (settingsRes.documents.length > 0 ? settingsRes.documents[0] : {}) as Settings;
|
||||
|
||||
const postsCount = settings.feed_news_count || 12;
|
||||
const cardSettings = {
|
||||
@ -26,7 +28,7 @@ async function fetchClasificadosData() {
|
||||
Query.equal('codigo', 'CLASIFICADO')
|
||||
]);
|
||||
|
||||
let posts: any[] = [];
|
||||
let posts: Post[] = [];
|
||||
if (typeRes.documents.length > 0) {
|
||||
const typeId = typeRes.documents[0].$id;
|
||||
const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [
|
||||
@ -35,16 +37,19 @@ async function fetchClasificadosData() {
|
||||
Query.orderDesc('fecha_publicacion'),
|
||||
Query.limit(postsCount)
|
||||
]);
|
||||
posts = postsRes.documents;
|
||||
posts = postsRes.documents as unknown as Post[];
|
||||
|
||||
// 3. Resolve Media
|
||||
const mediaIds = posts.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string');
|
||||
const mediaIds = posts.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string') as 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) }));
|
||||
const mediaMap = new Map<string, MediaItem>(mediaRes.documents.map(m => [m.$id, m as unknown as MediaItem]));
|
||||
posts = posts.map(p => ({
|
||||
...p,
|
||||
resolved_media: mediaMap.get(p.imagen_destacada_id as string)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,8 @@ import { Query } from 'node-appwrite';
|
||||
import { NewsCard } from '@/components/NewsCard';
|
||||
import { GlobalSidebar, hasSidebarContent } from '@/components/AdWrappers';
|
||||
import { Calendar } from 'lucide-react';
|
||||
import { Settings } from '@/types/settings';
|
||||
import { Post, MediaItem } from '@/types/publications';
|
||||
|
||||
async function fetchEventosData() {
|
||||
try {
|
||||
@ -11,7 +13,7 @@ async function fetchEventosData() {
|
||||
|
||||
// 1. Settings
|
||||
const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []);
|
||||
const settings: any = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {};
|
||||
const settings = (settingsRes.documents.length > 0 ? settingsRes.documents[0] : {}) as Settings;
|
||||
|
||||
const postsCount = settings.feed_news_count || 12;
|
||||
const cardSettings = {
|
||||
@ -26,7 +28,7 @@ async function fetchEventosData() {
|
||||
Query.equal('codigo', 'EVENTO')
|
||||
]);
|
||||
|
||||
let posts: any[] = [];
|
||||
let posts: Post[] = [];
|
||||
if (typeRes.documents.length > 0) {
|
||||
const typeId = typeRes.documents[0].$id;
|
||||
const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [
|
||||
@ -35,16 +37,19 @@ async function fetchEventosData() {
|
||||
Query.orderDesc('fecha_publicacion'),
|
||||
Query.limit(postsCount)
|
||||
]);
|
||||
posts = postsRes.documents;
|
||||
posts = postsRes.documents as unknown as Post[];
|
||||
|
||||
// 3. Resolve Media
|
||||
const mediaIds = posts.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string');
|
||||
const mediaIds = posts.map(p => p.imagen_destacada_id).filter(id => id && typeof id === 'string') as 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) }));
|
||||
const mediaMap = new Map<string, MediaItem>(mediaRes.documents.map(m => [m.$id, m as unknown as MediaItem]));
|
||||
posts = posts.map(p => ({
|
||||
...p,
|
||||
resolved_media: mediaMap.get(p.imagen_destacada_id as string)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,33 +6,31 @@ import { GlobalSidebar, hasSidebarContent } from '@/components/AdWrappers';
|
||||
import { RadioTower, Sparkles, ChevronDown } from 'lucide-react';
|
||||
import { decodeHtmlEntities } from '@/lib/utils';
|
||||
|
||||
import { Settings } from '@/types/settings';
|
||||
import { Post, MediaItem } from '@/types/publications';
|
||||
|
||||
async function fetchHomeData() {
|
||||
try {
|
||||
const client = await createAdminClient();
|
||||
|
||||
// 1. Settings with fallback
|
||||
let settings: any = {};
|
||||
try {
|
||||
const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', [Query.limit(1)]);
|
||||
settings = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {};
|
||||
} catch (e) {
|
||||
console.error("Settings fetch error", e);
|
||||
}
|
||||
// 1. Settings
|
||||
const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []);
|
||||
const settings = (settingsRes.documents.length > 0 ? settingsRes.documents[0] : {}) as Settings;
|
||||
|
||||
const postsCount = settings?.feed_news_count || 12;
|
||||
const postsCount = settings.feed_news_count || 12;
|
||||
const cardSettings = {
|
||||
showCategory: settings?.news_card_show_category ?? false,
|
||||
showFooterDate: settings?.show_news_date ?? true,
|
||||
showFooterButton: settings?.news_card_show_footer_button ?? true,
|
||||
footerText: settings?.news_card_footer_text || ""
|
||||
showCategory: settings.news_card_show_category ?? false,
|
||||
showFooterDate: settings.show_news_date ?? false,
|
||||
showFooterButton: settings.news_card_show_footer_button ?? true,
|
||||
footerText: settings.news_card_footer_text || ""
|
||||
};
|
||||
|
||||
// 2. Get NOTICIA type ID
|
||||
// 2. Main News (NOTICIA)
|
||||
const typeRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'publication_types', [
|
||||
Query.equal('codigo', 'NOTICIA')
|
||||
]);
|
||||
|
||||
let posts: any[] = [];
|
||||
let posts: Post[] = [];
|
||||
if (typeRes.documents.length > 0) {
|
||||
const typeId = typeRes.documents[0].$id;
|
||||
const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [
|
||||
@ -41,19 +39,18 @@ async function fetchHomeData() {
|
||||
Query.orderDesc('fecha_publicacion'),
|
||||
Query.limit(postsCount)
|
||||
]);
|
||||
posts = postsRes.documents;
|
||||
posts = postsRes.documents as unknown as Post[];
|
||||
|
||||
// 3. Resolve Media documents for images
|
||||
// 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)
|
||||
const mediaMap = new Map<string, MediaItem>(mediaRes.documents.map(m => [m.$id, m as unknown as MediaItem]));
|
||||
posts = posts.map(p => ({
|
||||
...p,
|
||||
resolved_media: mediaMap.get(p.imagen_destacada_id as string)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,11 +3,7 @@ import { createAdminClient } from '@/lib/appwrite.server';
|
||||
import TopBanner from './TopBanner';
|
||||
import ClientSidebars from './ClientSidebars';
|
||||
|
||||
interface Settings {
|
||||
rotation_seconds: number;
|
||||
ticker_count: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
import { Settings } from '@/types/settings';
|
||||
|
||||
async function fetchSettings(): Promise<Settings> {
|
||||
try {
|
||||
|
||||
@ -3,6 +3,7 @@ import { createSessionClient } from '@/lib/appwrite.server';
|
||||
import { Query } from 'node-appwrite';
|
||||
import Link from 'next/link';
|
||||
import { MessageCircle } from 'lucide-react';
|
||||
import { Settings } from '@/types/settings';
|
||||
|
||||
export default async function NewsTicker() {
|
||||
let tickerItems: any[] = [];
|
||||
@ -18,7 +19,7 @@ export default async function NewsTicker() {
|
||||
|
||||
// 1. Fetch Settings
|
||||
const settingsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'settings', []);
|
||||
const settings: any = settingsRes.documents.length > 0 ? settingsRes.documents[0] : {};
|
||||
const settings = (settingsRes.documents.length > 0 ? settingsRes.documents[0] : {}) as Settings;
|
||||
const tickerCount = settings.ticker_count || 10;
|
||||
|
||||
// 2. Fetch News (NOTICIA)
|
||||
|
||||
@ -80,6 +80,7 @@ export interface Post {
|
||||
tipo_publicacion_id: string | PublicationType;
|
||||
imagen_destacada_id?: string | MediaItem;
|
||||
cliente_id?: string | Client;
|
||||
resolved_media?: MediaItem;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
10
src/types/settings.ts
Normal file
10
src/types/settings.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @file settings.ts
|
||||
* @description Shared interfaces for Appwrite settings documents.
|
||||
*/
|
||||
|
||||
export interface Settings {
|
||||
rotation_seconds: number;
|
||||
ticker_count: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user