From 726c5d44ae3889e936d24d057715d4ab5c25a06e Mon Sep 17 00:00:00 2001 From: Alma Date: Sun, 13 Apr 2025 22:59:09 +0200 Subject: [PATCH] widget news fetch 6 --- app/api/news/route.ts | 88 +++++++++++++++++++++---------- components/news.tsx | 117 ++++++++++++++++++++++++++---------------- 2 files changed, 134 insertions(+), 71 deletions(-) diff --git a/app/api/news/route.ts b/app/api/news/route.ts index 5a3cc1c6..b4b1208c 100644 --- a/app/api/news/route.ts +++ b/app/api/news/route.ts @@ -6,35 +6,61 @@ function cleanDatabaseHost(host: string | undefined): string { if (!host) { throw new Error('Database host is not defined'); } - return host.replace(/^https?:\/\//, ''); + // Remove any protocol and trailing slashes + return host.replace(/^https?:\/\//, '').replace(/\/$/, ''); } -// Create a new pool using the environment variables -const pool = new Pool({ +// Create connection configuration +const dbConfig = { user: process.env.DB_USER, password: process.env.DB_PASSWORD, host: cleanDatabaseHost(process.env.DB_HOST), database: process.env.DB_NAME, + port: 5432, // Default PostgreSQL port ssl: { - rejectUnauthorized: false // Required for some cloud databases + rejectUnauthorized: false } -}); +}; + +// Create a new pool using the configuration +const pool = new Pool(dbConfig); export async function GET() { try { - // Log connection attempt - console.log('Attempting database connection with config:', { - user: process.env.DB_USER, - host: process.env.DB_HOST, - database: process.env.DB_NAME, - hasPassword: !!process.env.DB_PASSWORD - }); + // Log connection attempt with sanitized config + const sanitizedConfig = { + user: dbConfig.user, + host: dbConfig.host, + database: dbConfig.database, + port: dbConfig.port, + hasPassword: !!dbConfig.password, + ssl: !!dbConfig.ssl + }; + console.log('Attempting database connection with config:', sanitizedConfig); - // Connect to the database + // First test the connection const client = await pool.connect(); console.log('Successfully connected to database'); try { + // First check if the news table exists + console.log('Checking if news table exists...'); + const tableCheck = await client.query(` + SELECT EXISTS ( + SELECT FROM information_schema.tables + WHERE table_schema = 'public' + AND table_name = 'news' + ); + `); + + if (!tableCheck.rows[0].exists) { + console.error('News table does not exist'); + return NextResponse.json( + { error: 'News table does not exist in database' }, + { status: 500 } + ); + } + // Query the news table for the latest 10 news items console.log('Executing news query...'); const result = await client.query(` @@ -46,16 +72,19 @@ export async function GET() { source, description, category, - sentiment_score, + sentiment_score as "sentimentScore", sentiment, symbols, symbol FROM news ORDER BY date DESC - LIMIT 10 + LIMIT 10; `); console.log(`Query completed. Found ${result.rows.length} news items.`); + if (result.rows.length > 0) { + console.log('Sample first row:', result.rows[0]); + } // Format the response const news = result.rows.map(row => ({ @@ -67,10 +96,10 @@ export async function GET() { description: row.description, category: row.category, sentiment: { - score: row.sentiment_score, + score: row.sentimentScore, label: row.sentiment }, - symbols: row.symbols, + symbols: Array.isArray(row.symbols) ? row.symbols : null, symbol: row.symbol })); @@ -82,27 +111,34 @@ export async function GET() { { status: 500 } ); } finally { - // Release the client back to the pool client.release(); console.log('Database client released'); } } catch (error: any) { console.error('Database connection error:', error); + // Check if error is due to missing configuration - if (!process.env.DB_USER || !process.env.DB_PASSWORD || !process.env.DB_HOST || !process.env.DB_NAME) { - console.error('Missing database configuration:', { - hasUser: !!process.env.DB_USER, - hasPassword: !!process.env.DB_PASSWORD, - hasHost: !!process.env.DB_HOST, - hasDatabase: !!process.env.DB_NAME - }); + if (!dbConfig.user || !dbConfig.password || !dbConfig.host || !dbConfig.database) { + const missingConfig = { + user: !dbConfig.user, + password: !dbConfig.password, + host: !dbConfig.host, + database: !dbConfig.database + }; + console.error('Missing database configuration:', missingConfig); return NextResponse.json( { error: 'Database configuration is incomplete' }, { status: 500 } ); } + + // Return detailed error message return NextResponse.json( - { error: 'Failed to connect to database: ' + (error?.message || 'Unknown error') }, + { + error: 'Failed to connect to database', + details: error.message, + code: error.code + }, { status: 500 } ); } diff --git a/components/news.tsx b/components/news.tsx index 18433f67..f77c35d3 100644 --- a/components/news.tsx +++ b/components/news.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useState } from "react"; +import { useEffect, useState, useCallback } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { formatDistanceToNow } from 'date-fns'; import { fr } from 'date-fns/locale'; @@ -24,93 +24,120 @@ interface NewsItem { symbol: string | null; } +interface DebugState { + newsCount: number; + loading: boolean; + error: string | null; + dbStatus: string; + lastUpdate: string; + lastError: string | null; +} + export function News() { - console.log('[News] Component mounting...'); - const [news, setNews] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [refreshing, setRefreshing] = useState(false); const [dbStatus, setDbStatus] = useState<'connecting' | 'connected' | 'error'>('connecting'); + const [debugState, setDebugState] = useState({ + newsCount: 0, + loading: true, + error: null, + dbStatus: 'connecting', + lastUpdate: new Date().toISOString(), + lastError: null + }); - // Debug info display component - const DebugInfo = () => { - console.log('[News] Current state:', { - newsCount: news.length, - loading, - error, - dbStatus, - newsItems: news + const updateDebugState = useCallback((updates: Partial) => { + setDebugState(prev => { + const newState = { ...prev, ...updates, lastUpdate: new Date().toISOString() }; + console.table(newState); + return newState; }); - - return ( -
-

Status: {dbStatus}

-

Loading: {loading ? 'true' : 'false'}

-

Error: {error || 'none'}

-

News items: {news.length}

-
- Debug Details -
-            {JSON.stringify(news, null, 2)}
-          
-
-
- ); - }; + }, []); - const fetchNews = async (isRefresh = false) => { - console.log('[News] Fetching news, isRefresh:', isRefresh); + const fetchNews = useCallback(async (isRefresh = false) => { + updateDebugState({ loading: true, dbStatus: 'connecting' }); + + if (isRefresh) { + setRefreshing(true); + updateDebugState({ lastError: null }); + } - if (isRefresh) setRefreshing(true); setLoading(true); setDbStatus('connecting'); try { - console.log('[News] Making API request to /api/news'); - const response = await fetch('/api/news', { - method: 'GET', - headers: { - 'Accept': 'application/json', - }, - }); + updateDebugState({ dbStatus: 'fetching' }); + const response = await fetch('/api/news'); - console.log('[News] API response status:', response.status); + updateDebugState({ dbStatus: response.ok ? 'received' : 'error' }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); - console.log('[News] API response data:', data); if (data.error) { throw new Error(data.error); } - console.log('[News] Setting news items:', data.news); setNews(data.news || []); setError(null); setDbStatus('connected'); + + updateDebugState({ + newsCount: (data.news || []).length, + error: null, + dbStatus: 'connected', + loading: false + }); } catch (err) { - console.error('[News] Error fetching news:', err); const errorMessage = err instanceof Error ? err.message : 'Failed to load news'; setError(errorMessage); setDbStatus('error'); setNews([]); + + updateDebugState({ + error: errorMessage, + dbStatus: 'error', + loading: false, + lastError: errorMessage + }); } finally { setLoading(false); setRefreshing(false); } - }; + }, [updateDebugState]); useEffect(() => { - console.log('[News] Running useEffect...'); + updateDebugState({ dbStatus: 'initializing' }); fetchNews(); + return () => { - console.log('[News] Component unmounting...'); + updateDebugState({ dbStatus: 'unmounting' }); }; - }, []); + }, [fetchNews, updateDebugState]); + + const DebugInfo = () => ( +
+

Status: {debugState.dbStatus}

+

Loading: {debugState.loading ? 'true' : 'false'}

+

Error: {debugState.error || 'none'}

+

News items: {debugState.newsCount}

+

Last update: {new Date(debugState.lastUpdate).toLocaleTimeString()}

+ {debugState.lastError && ( +

Last error: {debugState.lastError}

+ )} +
+ Debug Details +
+          {JSON.stringify(news, null, 2)}
+        
+
+
+ ); if (loading && !refreshing) { return (