Skip to content

Commit 9eccde5

Browse files
committed
feat: Enhance author page with latest articles fetching, improved author summaries, and SEO metadata updates
1 parent 4def6e4 commit 9eccde5

1 file changed

Lines changed: 74 additions & 14 deletions

File tree

app/team/[author]/page.tsx

Lines changed: 74 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { db } from "@/lib/firebase";
2-
import { collection, query, where, getDocs, orderBy } from "firebase/firestore";
2+
import { collection, query, where, getDocs, orderBy, limit } from "firebase/firestore";
33
import PostNavigation from "@/components/PostNavigation";
44
import SocialSharing from "@/components/SocialSharing";
55
import Link from "next/link";
66
import JsonLd from "@/components/JsonLd";
77
import type { Metadata } from "next";
8+
import { notFound } from "next/navigation";
89
import {
910
SITE_LOCALE,
1011
SITE_NAME,
@@ -50,6 +51,43 @@ type ArticleData = {
5051
publish: boolean; // Added publish field
5152
};
5253

54+
function buildAuthorSummary(author: AuthorData) {
55+
const role = author.job || "team member";
56+
const city = author.city ? ` based in ${author.city}` : "";
57+
return `${author.name} is a ${role} on the ${SITE_NAME} team${city}.`;
58+
}
59+
60+
function buildAuthorBody(author: AuthorData) {
61+
const city = author.city ? ` Based in ${author.city},` : "";
62+
return `${city} ${author.name} contributes to ${SITE_NAME} by supporting tutorials, documentation, and the broader learning experience for the community.`.trim();
63+
}
64+
65+
async function getLatestPublishedArticles(count = 4) {
66+
const latestSnapshot = await getDocs(
67+
query(
68+
collection(db, "articles"),
69+
where("publish", "==", true),
70+
orderBy("date", "desc"),
71+
limit(count),
72+
),
73+
);
74+
75+
return latestSnapshot.docs.map((doc) => {
76+
const data = doc.data();
77+
return {
78+
uid: doc.id,
79+
title: data.title || "Untitled",
80+
img: data.img || "/default-image.png",
81+
date: data.date?.toDate?.() || new Date(),
82+
read: data.read || "Unknown",
83+
label: data.label || "No Label",
84+
slug: data.slug || "",
85+
authorUID: data.authorUID || "",
86+
publish: data.publish ?? false,
87+
} as ArticleData;
88+
});
89+
}
90+
5391
// Function to fetch author data
5492
async function getAuthorData(slug: string) {
5593
try {
@@ -60,7 +98,12 @@ async function getAuthorData(slug: string) {
6098

6199
if (authorSnapshot.empty) return null;
62100

63-
const authorData = authorSnapshot.docs[0].data() as AuthorData;
101+
const authorDoc = authorSnapshot.docs[0];
102+
const authorRaw = authorDoc.data();
103+
const authorData = {
104+
...authorRaw,
105+
uid: authorRaw.uid || authorDoc.id,
106+
} as AuthorData;
64107

65108
// Approach 1: Try with composite index (if you've created it in Firebase console)
66109
try {
@@ -155,13 +198,15 @@ export async function generateMetadata({
155198
const authorImage = authorData.avatar
156199
? absoluteUrl(authorData.avatar)
157200
: absoluteUrl("/default-avatar.png");
201+
const authorDescription =
202+
authorData.biography?.summary?.trim() || buildAuthorSummary(authorData);
158203

159204
return {
160205
title: `${authorData.name}`,
161-
description: authorData.biography.summary,
206+
description: authorDescription,
162207
openGraph: {
163208
title: `${authorData.name}`,
164-
description: authorData.biography.summary,
209+
description: authorDescription,
165210
url: authorUrl,
166211
siteName: SITE_NAME,
167212
locale: SITE_LOCALE,
@@ -176,7 +221,7 @@ export async function generateMetadata({
176221
twitter: {
177222
card: "summary_large_image",
178223
title: `${authorData.name}`,
179-
description: authorData.biography.summary,
224+
description: authorDescription,
180225
images: [authorImage],
181226
},
182227
alternates: {
@@ -195,10 +240,19 @@ export default async function Page({
195240
const data = await getAuthorData(author);
196241

197242
if (!data) {
198-
return <div className="p-8">Author not found</div>;
243+
notFound();
199244
}
200245

201246
const { author: authorData, articles } = data;
247+
const authoredArticles = articles;
248+
const fallbackArticles =
249+
authoredArticles.length === 0 ? await getLatestPublishedArticles() : [];
250+
const displayArticles =
251+
authoredArticles.length > 0 ? authoredArticles : fallbackArticles;
252+
const authorSummary =
253+
authorData.biography?.summary?.trim() || buildAuthorSummary(authorData);
254+
const authorBody =
255+
authorData.biography?.body?.trim() || buildAuthorBody(authorData);
202256

203257
// **Dynamically Generate Social Media Links**
204258
const socialLinks = authorData.socials
@@ -223,11 +277,11 @@ export default async function Page({
223277
name: authorData.name,
224278
jobTitle: authorData.job,
225279
image: authorData.avatar ? absoluteUrl(authorData.avatar) : undefined,
226-
description: authorData.biography.summary,
280+
description: authorSummary,
227281
url: authorUrl,
228282
sameAs: socialLinks.map((link) => link.href),
229283
worksFor: buildPublisherSchema(),
230-
hasPart: articles.map((article) => ({
284+
hasPart: authoredArticles.map((article) => ({
231285
"@type": "Article",
232286
headline: article.title,
233287
url: absoluteUrl(`/posts/${article.slug}`),
@@ -273,19 +327,25 @@ export default async function Page({
273327
<p className="text-blog-summary pb-12 text-white/50">
274328
{authorData.job}
275329
</p>
276-
<p className="text-blog-summary pb-12">
277-
{authorData.biography.summary}
278-
</p>
279-
<p className="text-blog-body">{authorData.biography.body}</p>
330+
<p className="text-blog-summary pb-12">{authorSummary}</p>
331+
<p className="text-blog-body">{authorBody}</p>
280332
</article>
281333
</article>
282334

283335
{/* **Author Articles** */}
284336
<div className="pb-12 md:pb-48">
285337
<h2 className="text-blog-subheading mt-[9.5rem] pt-12 pb-12 md:pb-24">
286-
Posts by {authorData.name}
338+
{authoredArticles.length > 0
339+
? `Posts by ${authorData.name}`
340+
: `Latest Posts on ${SITE_NAME}`}
287341
</h2>
288-
<AuthorArticles articles={articles} />
342+
{authoredArticles.length === 0 && (
343+
<p className="pb-8 text-white/70">
344+
{authorData.name} does not have published posts on the site yet, so
345+
we are showing the latest docs below.
346+
</p>
347+
)}
348+
<AuthorArticles articles={displayArticles} />
289349
</div>
290350
</main>
291351
);

0 commit comments

Comments
 (0)