Skip to content

Commit 89ac36e

Browse files
committed
feat: Implement dynamic article display pages with Firebase integration, SEO metadata generation, and core layout components.
1 parent 2250d6c commit 89ac36e

5 files changed

Lines changed: 58 additions & 43 deletions

File tree

app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export default function RootLayout({
7171
}: {
7272
children: React.ReactNode;
7373
}) {
74-
const GA_TRACKING_ID = process.env.MEASURING_ID || "";
74+
const GA_TRACKING_ID = process.env.NEXT_PUBLIC_MEASURING_ID || "";
7575

7676
return (
7777
<html lang="en" className="scroll-smooth">

app/posts/[title]/page.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -199,16 +199,16 @@ export default async function ArticleDetails({
199199
// Process article content
200200
const processedArticle: Article = {
201201
id: articleDoc.id,
202-
title: articleData.title,
203-
slug: articleData.slug,
204-
content: articleData.content,
202+
title: articleData.title || "Untitled",
203+
slug: articleData.slug || "",
204+
content: articleData.content || "",
205205
date: safeTimestampToDate(articleData.date),
206-
read: articleData.read,
207-
label: articleData.label,
208-
img: articleData.img,
209-
imgAlt: articleData.imgAlt,
210-
description: articleData.description,
211-
authorUID: articleData.authorUID,
206+
read: articleData.read || "Unknown",
207+
label: articleData.label || "",
208+
img: articleData.img || "/default-image.png",
209+
imgAlt: articleData.imgAlt || articleData.title || "Article image",
210+
description: articleData.description || "",
211+
authorUID: articleData.authorUID || "",
212212
authorName: authorData.name || "Unknown Author",
213213
authorAvatar: authorData.avatar || "/default-avatar.png",
214214
publish: false,

components/Header.tsx

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,26 @@ export default function Header() {
2323
// Fetch minimal article data on mount
2424
useEffect(() => {
2525
(async () => {
26-
const q = query(collection(db, "articles"), orderBy("date", "desc"));
27-
const snap = await getDocs(q);
28-
const items = snap.docs
29-
// only published
30-
.filter((d) => (d.data() as any).publish === true)
31-
.map((d) => {
32-
const data = d.data() as any;
33-
return {
34-
id: d.id,
35-
title: data.title,
36-
slug: data.slug,
37-
img: data.img,
38-
imgAlt: data.imgAlt || data.title,
39-
} as SearchItem;
40-
});
41-
setAllArticles(items);
26+
try {
27+
const q = query(collection(db, "articles"), orderBy("date", "desc"));
28+
const snap = await getDocs(q);
29+
const items = snap.docs
30+
// only published
31+
.filter((d) => (d.data() as any).publish === true)
32+
.map((d) => {
33+
const data = d.data() as any;
34+
return {
35+
id: d.id,
36+
title: data.title || "",
37+
slug: data.slug || "",
38+
img: data.img || "",
39+
imgAlt: data.imgAlt || data.title || "",
40+
} as SearchItem;
41+
});
42+
setAllArticles(items);
43+
} catch (error) {
44+
console.error("Error fetching articles for search:", error);
45+
}
4246
})();
4347
}, []);
4448

components/PopularArticles.tsx

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,32 @@ export default function PopularArticles({
4545
orderBy("popularityRank", "asc"),
4646
);
4747

48-
const unsubscribe = onSnapshot(articlesQuery, (snapshot) => {
49-
const articles: Article[] = snapshot.docs.map((doc) => {
50-
const data = doc.data();
51-
return {
52-
id: doc.id,
53-
...data,
54-
date:
55-
data.date instanceof Timestamp
56-
? data.date
57-
: (data.date ?? new Date().toISOString()),
58-
} as Article;
59-
});
48+
const unsubscribe = onSnapshot(
49+
articlesQuery,
50+
(snapshot) => {
51+
const articles: Article[] = snapshot.docs.map((doc) => {
52+
const data = doc.data();
53+
return {
54+
id: doc.id,
55+
title: data.title || "",
56+
slug: data.slug || "",
57+
authorName: data.authorName || "Unknown Author",
58+
popularity: data.popularity || false,
59+
publish: data.publish || false,
60+
date:
61+
data.date instanceof Timestamp
62+
? data.date
63+
: (data.date ?? new Date().toISOString()),
64+
popularityRank: data.popularityRank,
65+
} as Article;
66+
});
6067

61-
setPopularArticles(articles);
62-
});
68+
setPopularArticles(articles);
69+
},
70+
(error) => {
71+
console.error("Error listening to popular articles:", error);
72+
},
73+
);
6374

6475
return () => unsubscribe();
6576
}, []);

lib/firebase.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Import the functions you need from the SDKs you need
22
import { initializeApp } from "firebase/app";
33
// import { getAnalytics } from "firebase/analytics";
4-
import { getFirestore } from 'firebase/firestore';
4+
import { getFirestore } from "firebase/firestore";
55
// TODO: Add SDKs for Firebase products that you want to use
66
// https://firebase.google.com/docs/web/setup#available-libraries
77

@@ -14,12 +14,12 @@ const firebaseConfig = {
1414
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
1515
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
1616
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
17-
measurementId: process.env.MEASURING_ID,
17+
measurementId: process.env.NEXT_PUBLIC_MEASURING_ID,
1818
};
1919

2020
// Initialize Firebase
2121
const app = initializeApp(firebaseConfig);
2222
// const analytics = getAnalytics(app);
2323
const db = getFirestore(app);
2424

25-
export { db };
25+
export { db };

0 commit comments

Comments
 (0)