Skip to content

Commit d8300fc

Browse files
committed
fix: address CodeRabbit review comments
1 parent 555a75e commit d8300fc

8 files changed

Lines changed: 49 additions & 15 deletions

File tree

src/app/(public)/blog/[slug]/page.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Metadata } from "next";
22
import Image from "next/image";
33
import { notFound } from "next/navigation";
4+
import { cache } from "react";
45
import { desc, eq } from "drizzle-orm";
56
import PostContent, {
67
type TiptapJson,
@@ -13,6 +14,8 @@ import { getReadingTime } from "@/lib/utils";
1314

1415
export const revalidate = 3600;
1516

17+
const getCachedPostBySlug = cache(getPostBySlug);
18+
1619
type UpdatePageProps = {
1720
params: {
1821
slug: string;
@@ -56,7 +59,7 @@ export async function generateStaticParams() {
5659
export async function generateMetadata({
5760
params,
5861
}: UpdatePageProps): Promise<Metadata> {
59-
const post = await getPostBySlug(params.slug);
62+
const post = await getCachedPostBySlug(params.slug);
6063

6164
if (!post) {
6265
return {
@@ -90,7 +93,7 @@ export async function generateMetadata({
9093
}
9194

9295
export default async function UpdatePage({ params }: UpdatePageProps) {
93-
const post = await getPostBySlug(params.slug);
96+
const post = await getCachedPostBySlug(params.slug);
9497

9598
if (!post) {
9699
notFound();

src/app/api/upload/route.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ const allowedFolders = [
77
"products",
88
"blogs",
99
"blogs/inline",
10-
"general",
1110
] as const;
1211

1312
function isAllowedFolder(folder: string): folder is (typeof allowedFolders)[number] {
@@ -23,9 +22,9 @@ export async function POST(request: Request) {
2322

2423
try {
2524
const url = new URL(request.url);
26-
const folder = url.searchParams.get("folder") || "general";
25+
const folder = url.searchParams.get("folder");
2726

28-
if (!isAllowedFolder(folder)) {
27+
if (!folder || !isAllowedFolder(folder)) {
2928
return NextResponse.json({ error: "Invalid folder" }, { status: 400 });
3029
}
3130

src/components/admin/ImageUpload.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ export type UploadFolder =
99
| "team"
1010
| "products"
1111
| "blogs"
12-
| "blogs/inline"
13-
| "general";
12+
| "blogs/inline";
1413

1514
type ImageUploadProps = {
1615
value: string | null;
1716
onChange: (url: string) => void;
18-
folder?: UploadFolder;
17+
folder: UploadFolder;
1918
};
2019

2120
function getErrorMessage(value: unknown) {
@@ -34,7 +33,7 @@ function getErrorMessage(value: unknown) {
3433
export default function ImageUpload({
3534
value,
3635
onChange,
37-
folder = "general",
36+
folder,
3837
}: ImageUploadProps) {
3938
const inputRef = useRef<HTMLInputElement>(null);
4039
const [isUploading, setIsUploading] = useState(false);

src/components/admin/ResourceForms.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ export function TeamMemberForm({
191191
<Input label="Name" value={values.name} onChange={(event) => setValues({ ...values, name: event.target.value })} required />
192192
<Input label="Role" value={values.role} onChange={(event) => setValues({ ...values, role: event.target.value })} required />
193193
<Textarea label="Bio" value={values.bio} onChange={(event) => setValues({ ...values, bio: event.target.value })} required />
194-
<Input label="Photo URL" value={values.photo_url} onChange={(event) => setValues({ ...values, photo_url: event.target.value })} />
195194
<ImageUpload folder="team" value={values.photo_url || null} onChange={(url) => setValues({ ...values, photo_url: url })} />
196195
<div className="grid gap-4 md:grid-cols-3">
197196
<Input label="LinkedIn URL" value={values.linkedin_url} onChange={(event) => setValues({ ...values, linkedin_url: event.target.value })} />

src/components/admin/RichTextEditor.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ export default function RichTextEditor({
7474

7575
const formData = new FormData();
7676
formData.append("file", file);
77+
const uploadFolder = encodeURIComponent("blogs/inline");
7778

78-
const response = await fetch("/api/upload?folder=blogs%2Finline", {
79+
const response = await fetch(`/api/upload?folder=${uploadFolder}`, {
7980
method: "POST",
8081
body: formData,
8182
});

src/components/layout/Navbar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export default function Navbar() {
7070
onClick={() => setIsOpen((current) => !current)}
7171
>
7272
{isOpen ? (
73-
<CloseIcon className="h-5 w-5" />
73+
<CloseIcon className="h-6 w-6" />
7474
) : (
7575
<MenuIcon className="h-6 w-6" />
7676
)}

src/lib/cloudinary.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@ export function getOptimisedUrl(
66
return "";
77
}
88

9+
try {
10+
const parsedUrl = new URL(url);
11+
12+
if (
13+
!parsedUrl.hostname.endsWith("cloudinary.com") ||
14+
!parsedUrl.pathname.includes("/upload/")
15+
) {
16+
return url;
17+
}
18+
} catch {
19+
return url;
20+
}
21+
922
return url.replace("/upload/", `/upload/${transformation}/`);
1023
}
1124

src/lib/utils.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,29 @@ export function slugify(value: string) {
1616
}
1717

1818
export function getReadingTime(content: unknown): string {
19-
const text = JSON.stringify(content);
20-
const wordCount = text.split(/\s+/).length;
21-
const minutes = Math.ceil(wordCount / 200);
19+
function extractText(value: unknown): string {
20+
if (typeof value === "string") {
21+
return value;
22+
}
23+
24+
if (Array.isArray(value)) {
25+
return value.map(extractText).join(" ");
26+
}
27+
28+
if (value && typeof value === "object") {
29+
const node = value as { text?: unknown; content?: unknown };
30+
const ownText = typeof node.text === "string" ? node.text : "";
31+
const childText = extractText(node.content);
32+
33+
return `${ownText} ${childText}`.trim();
34+
}
35+
36+
return "";
37+
}
38+
39+
const text = extractText(content).trim();
40+
const wordCount = text ? text.split(/\s+/).length : 0;
41+
const minutes = wordCount === 0 ? 0 : Math.ceil(wordCount / 200);
2242

2343
return `${minutes} min read`;
2444
}

0 commit comments

Comments
 (0)