diff --git a/app.dockerfile b/app.dockerfile index 3433288..11503fe 100644 --- a/app.dockerfile +++ b/app.dockerfile @@ -1,5 +1,8 @@ FROM node:20.18.0-slim AS builder +ENV NEXT_PUBLIC_AWS_DB_API_URL=https://lyxeetk4w1.execute-api.us-east-1.amazonaws.com/default/getFromStockalyzerDB +ENV NEXT_PUBLIC_AWS_DB_API_KEY=0KcuAyP5zT8kk2vW4MXAU9lMi52Yorti4vRwLwia + WORKDIR /home/perplexica COPY package.json yarn.lock ./ diff --git a/src/app/news/page.tsx b/src/app/news/page.tsx new file mode 100644 index 0000000..665db18 --- /dev/null +++ b/src/app/news/page.tsx @@ -0,0 +1,136 @@ +'use client'; + +import { Search } from 'lucide-react'; +import { useEffect, useState } from 'react'; +import Image from 'next/image'; +import Link from 'next/link'; + +export interface News { + id: string; + title: string; + summary: string; + description: string; +} + +const API_BASE_URL = process.env.NEXT_PUBLIC_AWS_DB_API_URL || ''; +const API_URL = `${API_BASE_URL}?queryType=joint&num_results=20`; +const API_KEY = process.env.NEXT_PUBLIC_AWS_DB_API_KEY || ''; + +const NewsPageContent = () => { + const [news, setNews] = useState([]); + const [expanded, setExpanded] = useState<{ [key: string]: boolean }>({}); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchNews = async () => { + try { + const response = await fetch(API_URL, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': API_KEY, + }, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch news: ${response.statusText}`); + } + + const data = await response.json(); + + console.log("API Response:", data); // Debugging: Log the API response + + // Convert API response into News format + const formattedNews = data.result.map((item: any) => ({ + id: item[0], // Video ID (used in YouTube links) + title: item[1], // News title + description: item[3], // Short description + summary: item[4], // Full summary (for Show More) + })); + + setNews(formattedNews); + } catch (err) { + setError(err instanceof Error ? err.message : 'An unknown error occurred'); + } finally { + setLoading(false); + } + }; + + fetchNews(); + }, []); + + const toggleSummary = (id: string) => { + setExpanded((prev) => ({ ...prev, [id]: !prev[id] })); + }; + + if (loading) return

Loading news...

; + if (error) return

Error: {error}

; + + return ( +
+
+
+ +

Latest News

+
+
+
+ +
+ {news.map((item) => ( +
+
+ {/* Thumbnail on the Left */} +
+ +
+ + {/* Text on the Right */} +
+

{item.title}

+

+ {expanded[item.id] ? item.description : `${item.description.slice(0, 120)}...`} +

+ +
+
+ + {expanded[item.id] && ( +

{item.summary}

+ )} +
+ ))} +
+
+ ); +}; + +const NewsPage = () => { + return ( + <> + + + ); +}; + +export default NewsPage; \ No newline at end of file diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 5829c60..76b9e52 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -1,7 +1,7 @@ 'use client'; import { cn } from '@/lib/utils'; -import { BookOpenText, Home, Search, SquarePen, Settings } from 'lucide-react'; +import { BookOpenText, Home, Search, SquarePen, Settings, VideoIcon } from 'lucide-react'; import Link from 'next/link'; import { useSelectedLayoutSegments } from 'next/navigation'; import React, { useState, type ReactNode } from 'react'; @@ -35,6 +35,12 @@ const Sidebar = ({ children }: { children: React.ReactNode }) => { active: segments.includes('library'), label: 'Library', }, + { + icon: VideoIcon, + href: '/news', + active: segments.includes('news'), + label: 'News', + }, ]; return (