Skip to content

Commit d86ea76

Browse files
committed
feat: add initial pages and components for articles, authors, and posts.
1 parent 2e66467 commit d86ea76

8 files changed

Lines changed: 299 additions & 218 deletions

File tree

app/page.tsx

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import Subheading from "@/components/Subheading";
88
import { Suspense } from "react";
99
import type { Metadata } from "next";
1010
import JsonLd from "@/components/JsonLd";
11+
import { db } from "@/lib/firebase";
12+
import { collection, getDocs, query, orderBy, limit, Timestamp } from "firebase/firestore";
1113

1214
export const metadata: Metadata = {
1315
title: "L.A.P Docs | Home",
@@ -29,7 +31,92 @@ export const metadata: Metadata = {
2931
},
3032
};
3133

32-
export default function Home() {
34+
type Article = {
35+
id: string;
36+
title: string;
37+
slug: string;
38+
description: string;
39+
authorName: string;
40+
date: string | Timestamp;
41+
read: string;
42+
label: string;
43+
img: string;
44+
imgAlt: string;
45+
publish: boolean;
46+
};
47+
48+
type AuthorType = {
49+
id: string;
50+
slug: string;
51+
name: string;
52+
avatar: string;
53+
imgAlt: string;
54+
job: string;
55+
city: string;
56+
};
57+
58+
async function getData() {
59+
try {
60+
// Fetch latest articles
61+
const articlesQuery = query(
62+
collection(db, "articles"),
63+
orderBy("date", "desc")
64+
);
65+
const articlesSnapshot = await getDocs(articlesQuery);
66+
67+
// Fetch authors for mapping names
68+
const authorsSnapshot = await getDocs(collection(db, "authors"));
69+
const authorsMap = new Map(authorsSnapshot.docs.map(d => [d.id, d.data().name]));
70+
71+
const articles: Article[] = articlesSnapshot.docs
72+
.map((doc) => {
73+
const data = doc.data();
74+
return {
75+
id: doc.id,
76+
title: data.title || "",
77+
slug: data.slug || "",
78+
description: data.description || "",
79+
authorName: data.authorName || authorsMap.get(data.authorUID) || "Unknown Author",
80+
// Ensure date is a string. If it's a Timestamp, convert. If string, keep. Else current date.
81+
date: data.date instanceof Timestamp
82+
? data.date.toDate().toISOString()
83+
: (typeof data.date === 'string' ? data.date : new Date().toISOString()),
84+
read: data.read || "",
85+
label: data.label || "",
86+
img: data.img || "",
87+
imgAlt: data.imgAlt || "",
88+
publish: data.publish || false,
89+
} as Article;
90+
})
91+
.filter((a) => a.publish === true);
92+
93+
// Fetch all authors for the authors section - explicitly pick fields
94+
const allAuthors = authorsSnapshot.docs.map(doc => {
95+
const data = doc.data();
96+
return {
97+
id: doc.id,
98+
slug: data.slug || "",
99+
name: data.name || "",
100+
avatar: data.avatar || "",
101+
imgAlt: data.imgAlt || "",
102+
job: data.job || "",
103+
city: data.city || "",
104+
};
105+
});
106+
107+
// Shuffle authors
108+
const shuffledAuthors = [...allAuthors].sort(() => 0.5 - Math.random()).slice(0, 4);
109+
110+
return { articles, shuffledAuthors };
111+
} catch (error) {
112+
console.error("Error fetching home data:", error);
113+
return { articles: [], shuffledAuthors: [] };
114+
}
115+
}
116+
117+
export default async function Home() {
118+
const { articles, shuffledAuthors } = await getData();
119+
33120
const jsonLd = {
34121
"@context": "https://schema.org",
35122
"@type": "WebSite",
@@ -57,7 +144,7 @@ export default function Home() {
57144
<NewsTicker />
58145
</Suspense>
59146

60-
<LatestPosts />
147+
<LatestPosts initialPosts={articles} />
61148

62149
<Subheading
63150
className="text-subheading"
@@ -68,7 +155,7 @@ export default function Home() {
68155
</Subheading>
69156

70157
<Suspense fallback={<AuthorsLoading />}>
71-
<Authors />
158+
<Authors initialAuthors={shuffledAuthors} />
72159
</Suspense>
73160
</main>
74161
);

app/posts/[title]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ export default async function ArticleDetails({
254254
<PostNavigation href="/posts">POSTS</PostNavigation>
255255

256256
<article className="grid md:grid-cols-2 gap-6 md:gap-6 pb-6 md:pb-24">
257-
<h2 className="text-subtitle">{processedArticle.title}</h2>
257+
<h1 className="text-subtitle">{processedArticle.title}</h1>
258258
<p>{processedArticle.description}</p>
259259
</article>
260260

app/posts/page.tsx

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import PageTitle from "@/components/PageTitle";
44
import { Suspense } from "react";
55
import type { Metadata } from "next";
66
import JsonLd from "@/components/JsonLd";
7+
import { db } from "@/lib/firebase";
8+
import { collection, getDocs, query, orderBy } from "firebase/firestore";
79

810
export const metadata: Metadata = {
911
title: "Posts",
@@ -25,7 +27,84 @@ export const metadata: Metadata = {
2527
},
2628
};
2729

28-
export default function MagazinePage() {
30+
interface Article {
31+
id: string;
32+
title: string;
33+
label: string;
34+
date: string;
35+
img: string;
36+
imgAlt: string;
37+
slug: string;
38+
description: string;
39+
read: string;
40+
authorUID: string;
41+
authorName?: string;
42+
publish: boolean;
43+
}
44+
45+
async function getArticles() {
46+
try {
47+
// Fetch articles, ordered by date descending
48+
const articlesQuery = query(
49+
collection(db, "articles"),
50+
orderBy("date", "desc")
51+
);
52+
const articlesSnapshot = await getDocs(articlesQuery);
53+
54+
// Fetch authors
55+
const authorsSnapshot = await getDocs(collection(db, "authors"));
56+
// Create a map for faster lookup
57+
const authorsMap = new Map(authorsSnapshot.docs.map(doc => [doc.id, doc.data().name]));
58+
59+
const withAuthors = articlesSnapshot.docs
60+
.map((doc) => {
61+
const data = doc.data();
62+
let dateResult = "No date";
63+
64+
if (data.date) {
65+
if (data.date.toDate) {
66+
dateResult = data.date.toDate().toLocaleDateString("en-US", {
67+
year: "numeric",
68+
month: "long",
69+
day: "numeric",
70+
});
71+
} else if (typeof data.date === "string" || data.date instanceof Date) {
72+
dateResult = new Date(data.date).toLocaleDateString("en-US", {
73+
year: "numeric",
74+
month: "long",
75+
day: "numeric",
76+
});
77+
}
78+
}
79+
80+
return {
81+
id: doc.id,
82+
title: data.title || "",
83+
label: data.label || "",
84+
date: dateResult,
85+
img: data.img || "",
86+
imgAlt: data.imgAlt || "",
87+
slug: data.slug || "",
88+
description: data.description || "",
89+
read: data.read || "",
90+
authorUID: data.authorUID || "",
91+
authorName: authorsMap.get(data.authorUID) || "Unknown Author",
92+
publish: data.publish || false,
93+
} as Article;
94+
})
95+
// Filter out unpublished
96+
.filter((article) => article.publish === true);
97+
98+
return withAuthors;
99+
} catch (error) {
100+
console.error("Error fetching data:", error);
101+
return [];
102+
}
103+
}
104+
105+
export default async function MagazinePage() {
106+
const articles = await getArticles();
107+
29108
const jsonLd = {
30109
"@context": "https://schema.org",
31110
"@type": "CollectionPage",
@@ -45,7 +124,7 @@ export default function MagazinePage() {
45124
Posts
46125
</PageTitle>
47126
<Suspense fallback={<Loading />}>
48-
<Articles />
127+
<Articles initialArticles={articles} />
49128
</Suspense>
50129
</main>
51130
);

app/team/page.tsx

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { Suspense } from "react";
44
import Loading from "./loading";
55
import type { Metadata } from "next";
66
import JsonLd from "@/components/JsonLd";
7+
import { db } from "@/lib/firebase";
8+
import { collection, getDocs } from "firebase/firestore";
79

810
export const metadata: Metadata = {
911
title: "Team",
@@ -24,7 +26,41 @@ export const metadata: Metadata = {
2426
},
2527
};
2628

27-
export default function AuthorsPage() {
29+
type AuthorType = {
30+
uid: string;
31+
name: string;
32+
job: string;
33+
city: string;
34+
avatar: string;
35+
imgAlt: string;
36+
slug: string;
37+
};
38+
39+
async function getAuthors() {
40+
try {
41+
const querySnapshot = await getDocs(collection(db, "authors"));
42+
const fetchedAuthors = querySnapshot.docs.map((doc) => {
43+
const data = doc.data();
44+
return {
45+
uid: doc.id,
46+
name: data.name || "",
47+
job: data.job || "",
48+
city: data.city || "",
49+
avatar: data.avatar || "",
50+
imgAlt: data.imgAlt || "",
51+
slug: data.slug || "",
52+
};
53+
});
54+
return fetchedAuthors;
55+
} catch (error) {
56+
console.error("Error fetching authors:", error);
57+
return [];
58+
}
59+
}
60+
61+
export default async function AuthorsPage() {
62+
const authors = await getAuthors();
63+
2864
const jsonLd = {
2965
"@context": "https://schema.org",
3066
"@type": "CollectionPage",
@@ -44,7 +80,7 @@ export default function AuthorsPage() {
4480
Authors
4581
</PageTitle>
4682
<Suspense fallback={<Loading />}>
47-
<AuthorsList />
83+
<AuthorsList initialAuthors={authors} />
4884
</Suspense>
4985
</main>
5086
);

0 commit comments

Comments
 (0)