Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions src/__tests__/app/sitemap.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import sitemap from "@/app/sitemap";

const siteUrlEnvironmentKeys = [
"NEXT_PUBLIC_SITE_URL",
"NEXT_PUBLIC_APP_URL",
"VERCEL_PROJECT_PRODUCTION_URL",
"VERCEL_URL",
] as const;

const originalEnvironment = Object.fromEntries(
siteUrlEnvironmentKeys.map((key) => [key, process.env[key]]),
);

describe("sitemap", () => {
afterEach(() => {
for (const key of siteUrlEnvironmentKeys) {
const originalValue = originalEnvironment[key];
if (originalValue === undefined) {
delete process.env[key];
} else {
process.env[key] = originalValue;
}
}
});

it("preserves static route metadata without generated modification dates", () => {
for (const key of siteUrlEnvironmentKeys) {
delete process.env[key];
}

const entries = sitemap();
expect(entries.every((entry) => !("lastModified" in entry))).toBe(true);
expect(entries[0].url).toBe("https://doubt-desk-seven.vercel.app");
expect(entries[0].changeFrequency).toBe("weekly");
expect(entries[0].priority).toBe(1);
});

it("uses the configured site URL without introducing duplicate slashes", () => {
process.env.NEXT_PUBLIC_SITE_URL = "https://docs.example.com/";

const entries = sitemap();

expect(entries[0].url).toBe("https://docs.example.com");
expect(entries[1].url).toBe("https://docs.example.com/about");
expect(entries.every((entry) => !("lastModified" in entry))).toBe(true);
});
});
38 changes: 35 additions & 3 deletions src/app/(routes)/bookmarks/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { useEffect, useState } from "react";
import { Bookmark, Loader2, ArrowLeft, RefreshCw } from "lucide-react";
import { Bookmark, Loader2, ArrowLeft, RefreshCw, Search, X } from "lucide-react";
import DoubtCard from "@/components/classroom/DoubtCard";
import { useRouter } from "next/navigation";
import { useAppUser } from "@/app/provider";
Expand All @@ -21,6 +21,7 @@ export default function BookmarksPage() {
const [bookmarks, setBookmarks] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [searchQuery, setSearchQuery] = useState("");
const router = useRouter();
const { appUser } = useAppUser();
const { isLoaded, isSignedIn } = useAuth();
Expand Down Expand Up @@ -54,6 +55,15 @@ export default function BookmarksPage() {
fetchBookmarks();
}, [isLoaded, isSignedIn]);

const filteredBookmarks = bookmarks.filter((doubt) => {
if (!searchQuery.trim()) return true;
const q = searchQuery.toLowerCase();
return (
doubt.subject?.toLowerCase().includes(q) ||
doubt.content?.toLowerCase().includes(q)
);
});

return (
<>
<SignedIn>
Expand Down Expand Up @@ -86,6 +96,28 @@ export default function BookmarksPage() {
</div>
</header>

{!loading && !error && bookmarks.length > 0 && (
<div className="relative">
<Search className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400 dark:text-zinc-500 pointer-events-none" />
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search bookmarks by subject or content..."
className="w-full pl-11 pr-10 py-3 rounded-xl border border-slate-200 dark:border-zinc-800 bg-slate-50 dark:bg-zinc-900 text-slate-900 dark:text-white placeholder:text-slate-400 dark:placeholder:text-zinc-500 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-purple-500/40 transition-all"
/>
{searchQuery && (
<button
onClick={() => setSearchQuery("")}
className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-700 dark:hover:text-white transition-colors"
aria-label="Clear search"
>
<X className="w-4 h-4" />
</button>
)}
</div>
)}

{loading ? (
<div className="flex flex-col items-center justify-center py-24 space-y-4">
<Loader2 className="w-8 h-8 text-purple-500 animate-spin" />
Expand All @@ -112,9 +144,9 @@ export default function BookmarksPage() {
{UI_TEXT.RETRY_BUTTON}
</button>
</div>
) : bookmarks.length > 0 ? (
) : filteredBookmarks.length > 0 ? (
<div className="flex flex-col gap-6 lg:gap-8">
{bookmarks.map((doubt) => (
{filteredBookmarks.map((doubt) => (
<DoubtCard
key={doubt.id}
doubt={doubt}
Expand Down
87 changes: 0 additions & 87 deletions src/app/doubts/[id]/DoubtPermalinkClient.tsx

This file was deleted.

132 changes: 0 additions & 132 deletions src/app/doubts/[id]/page.tsx

This file was deleted.

Loading
Loading