Merge pull request #5 from newspedia-crew/intern-change

Change the logic of loading file
This commit is contained in:
guanghechen 2024-07-12 16:01:13 +08:00 committed by GitHub
commit ebfae3abd8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 115 additions and 37 deletions

View file

@ -1,2 +1,2 @@
NEXT_PUBLIC_WS_URL=ws://localhost:3001 NEXT_PUBLIC_WS_URL=ws://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:3001/api NEXT_PUBLIC_API_URL=http://localhost:3000/api

View file

@ -0,0 +1,22 @@
import { NextResponse } from "next/server";
import fs from "node:fs/promises";
import path from "node:path";
import { VALIDATED_ENV } from "../../../../lib/constants";
export async function GET(request: Request, { params }: { params: { id: string } }) {
try {
console.log(`Fetching news data for id: ${params.id}`);
console.log(`API URL: ${VALIDATED_ENV.API_URL}`); // Log the API URL
const dataDirectory = path.join(process.cwd(), "public", "data");
const filePath = path.join(dataDirectory, `${params.id}.json`);
const fileContents = await fs.readFile(filePath, "utf8");
const newsData = JSON.parse(fileContents);
return NextResponse.json(newsData);
} catch (error) {
console.error("Error reading news data:", error);
console.log(`WS URL: ${VALIDATED_ENV.WS_URL}`); // Log the WebSocket URL, just as an example
return NextResponse.json({ error: "News not found" }, { status: 404 });
}
}

16
ui/app/api/news/route.ts Normal file
View file

@ -0,0 +1,16 @@
import { NextResponse } from "next/server";
import fs from "node:fs/promises";
import path from "node:path";
export async function GET() {
try {
const dataDirectory = path.join(process.cwd(), "public", "data");
const filePath = path.join(dataDirectory, "index.json");
const fileContents = await fs.readFile(filePath, "utf8");
const data = JSON.parse(fileContents);
return NextResponse.json(data);
} catch (error) {
console.error("Error reading news data:", error);
return NextResponse.json({ error: "Failed to load news data" }, { status: 500 });
}
}

View file

@ -1,17 +1,15 @@
import Link from "next/link"; import { Metadata } from "next";
import { ArrowLeft } from "lucide-react"; import React from "react";
import { ENV, assertEnvVariables } from "../../../lib/constants";
export default function NewsDetailLayout({ children }: { children: React.ReactNode }) { export const metadata: Metadata = {
return ( title: "News - Perplexica",
<div className="max-w-4xl mx-auto p-4"> };
<Link
href="/news" assertEnvVariables(ENV);
className="inline-flex items-center mb-4 text-sm font-medium text-black dark:text-white hover:underline"
> const Layout = ({ children }: { children: React.ReactNode }) => {
<ArrowLeft className="w-4 h-4 mr-1" /> return <div>{children}</div>;
Back };
</Link>
{children} export default Layout;
</div>
);
}

View file

@ -1,11 +1,19 @@
import { fetchNewsData } from "../../../lib/fetchNewsData";
import NewsDetail from "../../../components/NewsDetail"; import NewsDetail from "../../../components/NewsDetail";
import { VALIDATED_ENV } from "../../../lib/constants";
async function getNewsData(id: string) {
const res = await fetch(`${VALIDATED_ENV.API_URL}/news/${id}`, { next: { revalidate: 60 } });
if (!res.ok) {
throw new Error("Failed to fetch news");
}
return res.json();
}
export default async function NewsPage({ params }: { params: { id: string } }) { export default async function NewsPage({ params }: { params: { id: string } }) {
const newsData = await fetchNewsData(params.id); const newsData = await getNewsData(params.id);
if (!newsData) { if (!newsData) {
return <div>News not found</div>; return <div className="text-center text-red-500">News not found or failed to load</div>;
} }
return <NewsDetail news={newsData} />; return <NewsDetail news={newsData} />;

View file

@ -7,7 +7,14 @@ interface ContextItemProperties {
name: string; name: string;
url: string; url: string;
description: string; description: string;
provider: { name: string; image?: { thumbnail: { contentUrl: string } } }[]; provider: {
name: string;
image?: {
thumbnail: {
contentUrl: string;
};
};
}[];
datePublished: string; datePublished: string;
image?: { image?: {
contentUrl: string; contentUrl: string;
@ -32,11 +39,30 @@ const ContextItem: React.FC<ContextItemProperties> = ({ item }) => {
<div className="text-black dark:text-white"> <div className="text-black dark:text-white">
<ReactMarkdown text={item.description} /> <ReactMarkdown text={item.description} />
</div> </div>
<a href={item.url} target="_blank" rel="noopener noreferrer" className="text-blue-500 hover:underline"> <a
href={item.url}
target="_blank"
rel="noopener noreferrer"
className="text-black dark:text-white hover:underline inline-block mt-2"
>
Read more Read more
</a> </a>
<div className="text-sm text-gray-500 dark:text-gray-400 mt-2"> <div className="mt-2">
{item.provider[0].name} | {new Date(item.datePublished).toLocaleDateString()} <div className="flex items-center text-sm text-gray-700 dark:text-gray-300">
{item.provider[0].image && (
<Image
src={item.provider[0].image.thumbnail.contentUrl}
alt={`${item.provider[0].name} logo`}
width={16}
height={16}
className="mr-2"
/>
)}
{item.provider[0].name}
</div>
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1">
{new Date(item.datePublished).toLocaleDateString()}
</div>
</div> </div>
</div> </div>
); );

View file

@ -19,9 +19,7 @@ const NewsPage = () => {
const fetchNews = async () => { const fetchNews = async () => {
try { try {
console.log("Fetching news..."); console.log("Fetching news...");
const response = await fetch( const response = await fetch("/api/news");
"https://raw.githubusercontent.com/newspedia-crew/newspedia-web/intern-change/public/data/index.json",
);
console.log("Response status:", response.status); console.log("Response status:", response.status);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);

19
ui/lib/constants.ts Normal file
View file

@ -0,0 +1,19 @@
export const ENV = {
WS_URL: process.env.NEXT_PUBLIC_WS_URL || "ws://localhost:3000",
API_URL: process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000/api",
} as const;
export type ENV = typeof ENV;
// Type guard function
export function assertEnvVariables(ENV: ENV): asserts ENV is Required<ENV> {
const missingVariables = Object.entries(ENV).filter(([_, value]) => value === undefined);
if (missingVariables.length > 0) {
console.warn(`Warning: Missing environment variables: ${missingVariables.map(([key]) => key).join(", ")}`);
console.warn("Using default values for missing variables.");
}
}
assertEnvVariables(ENV);
export const VALIDATED_ENV: Required<ENV> = ENV as Required<ENV>;

View file

@ -1,9 +0,0 @@
export async function fetchNewsData(id: string) {
const response = await fetch(
`https://raw.githubusercontent.com/newspedia-crew/newspedia-web/intern-change/public/data/${id}.json`,
);
if (!response.ok) {
return null;
}
return response.json();
}