Skip to content

Commit f71f4b4

Browse files
author
Shoaib Sharif
authored
Merge pull request #64 from techdiary-dev/issue/tag_archieve
Issue/tag archieve
2 parents 1f92575 + 60a4e1a commit f71f4b4

File tree

6 files changed

+71
-33
lines changed

6 files changed

+71
-33
lines changed

src/app/(home)/_components/ArticleFeed.tsx

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
"use client";
22

33
import * as articleActions from "@/backend/services/article.actions";
4-
import * as seriesActions from "@/backend/services/series.action";
54
import ArticleCard from "@/components/ArticleCard";
6-
import SeriesCard from "@/components/SeriesCard";
75
import VisibilitySensor from "@/components/VisibilitySensor";
86
import { readingTime } from "@/lib/utils";
97
import getFileUrl from "@/utils/getFileUrl";
108
import { useInfiniteQuery } from "@tanstack/react-query";
11-
import { Loader } from "lucide-react";
129
import { useState } from "react";
1310

1411
const ArticleFeed = () => {
@@ -53,10 +50,22 @@ const ArticleFeed = () => {
5350
<div className="flex flex-col gap-10 mt-2">
5451
{articleFeedQuery.isPending && (
5552
<>
56-
<div className="h-56 bg-muted animate-pulse mx-4" />
57-
<div className="h-56 bg-muted animate-pulse mx-4" />
58-
<div className="h-56 bg-muted animate-pulse mx-4" />
59-
<div className="h-56 bg-muted animate-pulse mx-4" />
53+
<div
54+
className="h-56 bg-muted animate-pulse mx-4"
55+
suppressHydrationWarning={true}
56+
/>
57+
<div
58+
className="h-56 bg-muted animate-pulse mx-4"
59+
suppressHydrationWarning={true}
60+
/>
61+
<div
62+
className="h-56 bg-muted animate-pulse mx-4"
63+
suppressHydrationWarning={true}
64+
/>
65+
<div
66+
className="h-56 bg-muted animate-pulse mx-4"
67+
suppressHydrationWarning={true}
68+
/>
6069
</>
6170
)}
6271

src/app/(home)/_components/HomeLeftSidebar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ const tags = [
9696
{
9797
icon: "https://res.cloudinary.com/techdiary-dev/image/upload/v1620782239/static-assets/tag-icons/erfbu54l2mquphszheck.svg",
9898
label: "react",
99-
link: "/tags/186e052a-9c5b-4ffe-b753-ea172ac2e663",
99+
link: "/tags/reactjs",
100100
},
101101
{
102102
icon: "https://res.cloudinary.com/techdiary-dev/image/upload/v1620782240/static-assets/tag-icons/rh7xfiz28bxklfzymftd.svg",

src/app/tags/[tag_id]/_components/TagArticleFeed.tsx renamed to src/app/tags/[tag_name]/_components/TagArticleFeed.tsx

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
"use client";
22

3+
import { Tag } from "@/backend/models/domain-models";
34
import * as articleActions from "@/backend/services/article.actions";
45
import ArticleCard from "@/components/ArticleCard";
56
import VisibilitySensor from "@/components/VisibilitySensor";
7+
import { useTranslation } from "@/i18n/use-translation";
68
import { readingTime } from "@/lib/utils";
79
import getFileUrl from "@/utils/getFileUrl";
810
import { useInfiniteQuery } from "@tanstack/react-query";
9-
import { useMemo } from "react";
11+
import React, { useMemo } from "react";
1012

1113
interface TagArticleFeedProps {
12-
tagId: string;
14+
tag: Tag;
1315
}
1416

15-
const TagArticleFeed: React.FC<TagArticleFeedProps> = ({ tagId }) => {
17+
const TagArticleFeed: React.FC<TagArticleFeedProps> = ({ tag }) => {
18+
const { _t } = useTranslation();
1619
const tagFeedQuery = useInfiniteQuery({
17-
queryKey: ["tag-articles", tagId],
20+
queryKey: ["tag-articles", tag.id],
1821
queryFn: ({ pageParam }) =>
1922
articleActions.articlesByTag({
20-
tag_id: tagId,
23+
tag_id: tag.id,
2124
limit: 5,
2225
page: pageParam,
2326
}),
@@ -37,18 +40,14 @@ const TagArticleFeed: React.FC<TagArticleFeedProps> = ({ tagId }) => {
3740
return tagFeedQuery.data?.pages?.[0]?.meta?.total ?? 0;
3841
}, [tagFeedQuery.data]);
3942

40-
const tagName = useMemo(() => {
41-
return tagFeedQuery.data?.pages?.[0]?.tagName ?? "Unknown Tag";
42-
}, [tagFeedQuery.data]);
43-
4443
// Show loading skeletons
4544
if (tagFeedQuery.isPending) {
4645
return (
4746
<div className="flex flex-col gap-10 mt-2">
48-
<div className="h-56 bg-muted animate-pulse mx-4" />
49-
<div className="h-56 bg-muted animate-pulse mx-4" />
50-
<div className="h-56 bg-muted animate-pulse mx-4" />
51-
<div className="h-56 bg-muted animate-pulse mx-4" />
47+
<div className="h-56 bg-muted animate-pulse mx-4" suppressHydrationWarning={true} />
48+
<div className="h-56 bg-muted animate-pulse mx-4" suppressHydrationWarning={true} />
49+
<div className="h-56 bg-muted animate-pulse mx-4" suppressHydrationWarning={true} />
50+
<div className="h-56 bg-muted animate-pulse mx-4" suppressHydrationWarning={true} />
5251
</div>
5352
);
5453
}
@@ -78,10 +77,10 @@ const TagArticleFeed: React.FC<TagArticleFeedProps> = ({ tagId }) => {
7877
return (
7978
<div className="flex flex-col items-center justify-center py-12">
8079
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">
81-
No articles found
80+
{_t("No articles found")}
8281
</h2>
8382
<p className="text-gray-600 dark:text-gray-400">
84-
No articles have been tagged with &ldquo;{tagName}&rdquo; yet.
83+
{_t(`No articles have been tagged with "$" yet.`, [tag.name])}
8584
</p>
8685
</div>
8786
);
@@ -91,10 +90,10 @@ const TagArticleFeed: React.FC<TagArticleFeedProps> = ({ tagId }) => {
9190
<>
9291
<div className="mb-8">
9392
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
94-
Articles tagged with &ldquo;{tagName}&rdquo;
93+
{_t(`Articles tagged with "$"`, [tag.name])}
9594
</h1>
9695
<p className="text-gray-600 dark:text-gray-400 mt-2">
97-
Found {totalArticles} articles
96+
{_t(`Found $ articles`, [totalArticles])}
9897
</p>
9998
</div>
10099

@@ -106,7 +105,9 @@ const TagArticleFeed: React.FC<TagArticleFeedProps> = ({ tagId }) => {
106105
handle={article?.handle ?? ""}
107106
title={article?.title ?? ""}
108107
excerpt={article?.excerpt ?? ""}
109-
coverImage={article?.cover_image ? getFileUrl(article.cover_image) : ""}
108+
coverImage={
109+
article?.cover_image ? getFileUrl(article.cover_image) : ""
110+
}
110111
author={{
111112
id: article?.user?.id ?? "",
112113
name: article?.user?.name ?? "",
@@ -133,4 +134,4 @@ const TagArticleFeed: React.FC<TagArticleFeedProps> = ({ tagId }) => {
133134
);
134135
};
135136

136-
export default TagArticleFeed;
137+
export default TagArticleFeed;
Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,22 @@ import HomeRightSidebar from "@/app/(home)/_components/HomeRightSidebar";
33
import SidebarToggleButton from "@/app/(home)/_components/SidebarToggleButton";
44
import HomepageLayout from "@/components/layout/HomepageLayout";
55
import TagArticleFeed from "./_components/TagArticleFeed";
6+
import { getTag, getTags } from "@/backend/services/tag.action";
7+
import { notFound } from "next/navigation";
68

79
interface TagPageProps {
810
params: Promise<{
9-
tag_id: string;
11+
tag_name: string;
1012
}>;
1113
}
1214

1315
export default async function TagPage({ params }: TagPageProps) {
14-
const { tag_id } = await params;
16+
const { tag_name } = await params;
17+
const tag = await getTag({ name: tag_name });
18+
19+
if (!tag?.success) {
20+
throw notFound();
21+
}
1522

1623
return (
1724
<HomepageLayout
@@ -20,21 +27,21 @@ export default async function TagPage({ params }: TagPageProps) {
2027
NavbarTrailing={<SidebarToggleButton />}
2128
>
2229
<div className="px-4 py-6">
23-
<TagArticleFeed tagId={tag_id} />
30+
<TagArticleFeed tag={tag.data} />
2431
</div>
2532
</HomepageLayout>
2633
);
2734
}
2835

2936
export async function generateMetadata({ params }: TagPageProps) {
30-
const { tag_id } = await params;
37+
const { tag_name } = await params;
3138

3239
// For now, use tag_id in the title. Later we can fetch the tag name if needed
3340
return {
34-
title: `Tag ${tag_id} - Tech Diary`,
41+
title: `Tag ${tag_name} - Tech Diary`,
3542
description: `Browse all articles with this tag on Tech Diary`,
3643
openGraph: {
37-
title: `Tag ${tag_id} - Tech Diary`,
44+
title: `Tag ${tag_name} - Tech Diary`,
3845
description: `Browse all articles with this tag on Tech Diary`,
3946
},
4047
};

src/backend/services/inputs/tag.input.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ export const TagRepositoryInput = {
1212
color: z.string().optional().nullable(),
1313
description: z.string().optional().nullable(),
1414
}),
15+
getTag: z.object({
16+
name: z.string(),
17+
}),
1518
updateInput: z.object({
1619
tag_id: z.string(),
1720
name: z.string().optional(),

src/backend/services/tag.action.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,24 @@ export const getTags = async (
2525
}
2626
};
2727

28+
export const getTag = async (
29+
_input: z.infer<typeof TagRepositoryInput.getTag>
30+
) => {
31+
try {
32+
const input = await TagRepositoryInput.createInput.parseAsync(_input);
33+
const response = await persistenceRepository.tags.find({
34+
where: eq("name", input.name),
35+
});
36+
37+
return {
38+
data: response[0],
39+
success: true as const,
40+
};
41+
} catch (error) {
42+
handleActionException(error);
43+
}
44+
};
45+
2846
export const createTag = async (
2947
_input: z.infer<typeof TagRepositoryInput.createInput>
3048
) => {

0 commit comments

Comments
 (0)