diff --git a/src/app/(routes)/public-rooms/[subject]/page.tsx b/src/app/(routes)/public-rooms/[subject]/page.tsx
index f7e74302..21bed679 100644
--- a/src/app/(routes)/public-rooms/[subject]/page.tsx
+++ b/src/app/(routes)/public-rooms/[subject]/page.tsx
@@ -23,143 +23,4 @@ export default function PublicRoomPage() {
const sort = (searchParams.get("sort") as DoubtSortValue) || "newest";
const fetcher = (url: string) => fetch(url).then(res => res.json());
- const updateSort = (nextSort: DoubtSortValue) => {
- const nextParams = new URLSearchParams(searchParams.toString());
- if (nextSort === "newest") {
- nextParams.delete("sort");
- } else {
- nextParams.set("sort", nextSort);
- }
-
- const query = nextParams.toString();
- router.replace(query ? `${pathname}?${query}` : pathname, { scroll: false });
- setSize(1);
- };
-
- const getKey = (pageIndex: number, previousPageData: any) => {
- if (previousPageData) {
- const hasMore = Array.isArray(previousPageData)
- ? previousPageData.length === PAGE_SIZE
- : previousPageData.hasMore;
- if (!hasMore) return null;
- }
- const params = new URLSearchParams({
- subject,
- page: String(pageIndex + 1),
- limit: String(PAGE_SIZE),
- });
-
- if (sort !== "newest") {
- params.append("sort", sort);
- }
-
- return `/api/doubts?${params.toString()}`;
- };
-
- const { data, isLoading, size, setSize, mutate } = useSWRInfinite(getKey, fetcher, {
- revalidateFirstPage: false
- });
-
- const doubts = data
- ? data.flatMap((page: any) =>
- page
- ? Array.isArray(page)
- ? page
- : (page.doubts || [])
- : []
- )
- : [];
- const isLoadingMore = isLoading || (size > 0 && data && typeof data[size - 1] === "undefined");
- const lastPage = data ? data[data.length - 1] : null;
- const isReachingEnd =
- data &&
- (Array.isArray(lastPage)
- ? lastPage.length < PAGE_SIZE
- : !lastPage?.hasMore);
-
- const { ref: loadMoreRef, inView } = useInView();
-
- useEffect(() => {
- if (inView && !isReachingEnd && !isLoadingMore) {
- setSize(size + 1);
- }
- }, [inView, isReachingEnd, isLoadingMore]);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
- {isLoading && doubts.length === 0 ? (
-
- ) : doubts.length > 0 ? (
-
-
- {doubts.map((doubt: any, index: number) => (
- mutate()} />
- ))}
-
-
- {isLoadingMore && }
-
-
- ) : (
-
-
-
-
-
No doubts yet!
-
- Be the first to start a conversation in the {subject} room. All posts are anonymous.
-
-
setIsAskModalOpen(true)}
- aria-label="Post the first doubt"
- className="px-6 py-3.5 bg-slate-50 dark:bg-zinc-900 border border-slate-200 dark:border-zinc-800 text-slate-700 dark:text-zinc-300 hover:bg-slate-100 dark:hover:bg-zinc-800/60 rounded-xl font-bold uppercase tracking-wider text-xs transition-all duration-300 shadow-sm"
- >
- Post the first doubt
-
-
- )}
-
- {isAskModalOpen && (
-
setIsAskModalOpen(false)}
- onSuccess={() => {
- setIsAskModalOpen(false);
- mutate();
- }}
- />
- )}
-
- );
-}
\ No newline at end of file
+ .catch(err => console.error(err))
\ No newline at end of file
diff --git a/src/app/(routes)/public-rooms/page.tsx b/src/app/(routes)/public-rooms/page.tsx
index 08556c80..537a6206 100644
--- a/src/app/(routes)/public-rooms/page.tsx
+++ b/src/app/(routes)/public-rooms/page.tsx
@@ -63,427 +63,4 @@ export default function PublicRoomsPage() {
const sort = (searchParams.get("sort") as DoubtSortValue) || "newest";
const fetcher = (url: string) => fetch(url).then(res => res.json());
-
- const updateSort = (nextSort: DoubtSortValue) => {
- const params = new URLSearchParams(searchParams.toString());
- if (nextSort === "newest") {
- params.delete("sort");
- } else {
- params.set("sort", nextSort);
- }
-
- const query = params.toString();
- router.replace(query ? `${pathname}?${query}` : pathname, { scroll: false });
- setSize(1);
- };
-
- const getKey = (pageIndex: number, previousPageData: any) => {
- if (previousPageData) {
- const hasMore = Array.isArray(previousPageData)
- ? previousPageData.length === PAGE_SIZE
- : previousPageData.hasMore;
- if (!hasMore) return null;
- }
-
- const params = new URLSearchParams();
-
- if (filter !== "All") {
- if (filter === "Bookmarked") {
- params.append("bookmarked", "true");
- } else {
- const subjectFilter = filter === "Others" ? appliedCustomFilter : filter;
- if (subjectFilter) params.append("subject", subjectFilter);
- }
- }
-
- if (searchQuery) {
- params.append("search", searchQuery);
- }
-
- if (appliedTagFilter.trim()) {
- params.append("tag", appliedTagFilter.trim());
- }
-
- if (sort !== "newest") {
- params.append("sort", sort);
- }
-
- params.append("page", (pageIndex + 1).toString());
- params.append("limit", String(PAGE_SIZE));
-
- return `/api/doubts?${params.toString()}`;
- };
-
- const fetchDoubts = async () => {
- setAppliedTagFilter(tagFilter);
- mutate();
- };
-
- const { data, isLoading, size, setSize, mutate } = useSWRInfinite(getKey, fetcher, {
- revalidateFirstPage: false
- });
-
- const doubts = (data
- ? data.flatMap((page: any) =>
- page
- ? Array.isArray(page)
- ? page
- : (page.doubts || [])
- : []
- )
- : []) as Doubt[];
-
- // Apply local filters to pending doubts so they match the active view
- const matchingPendingDoubts = pendingDoubts.filter((d) => {
- // 1. Subject filter
- if (filter !== "All") {
- if (filter === "Bookmarked") {
- // Pending doubts are not synced yet, so they cannot be bookmarked
- return false;
- } else if (filter === "Others") {
- const knownSubjects = ["Math", "Science", "Physics", "Chemistry", "Programming"];
- const isOtherSubject = !knownSubjects.includes(d.subject);
- if (appliedCustomFilter) {
- return d.subject?.toLowerCase() === appliedCustomFilter.toLowerCase();
- }
- return isOtherSubject;
- } else {
- return d.subject?.toLowerCase() === filter.toLowerCase();
- }
- }
-
- // 2. Search query filter
- if (searchQuery) {
- const query = searchQuery.toLowerCase();
- const contentMatch = d.content?.toLowerCase().includes(query);
- const subjectMatch = d.subject?.toLowerCase().includes(query);
- if (!contentMatch && !subjectMatch) {
- return false;
- }
- }
-
- // 3. Tag filter
- if (appliedTagFilter.trim()) {
- const normalizedTag = appliedTagFilter.trim().toLowerCase();
- const hasMatchingTag = d.tags?.some((t: any) => t.name?.toLowerCase() === normalizedTag);
- if (!hasMatchingTag) {
- return false;
- }
- }
-
- return true;
- });
-
- const allDoubts = [...matchingPendingDoubts, ...doubts];
- const filteredDoubts = (allDoubts as any[]).filter((d) => {
- if (statusFilter === 'all') return true;
- if (statusFilter === 'unsolved') return d.isSolved === 'unsolved' || !d.isSolved;
- if (statusFilter === 'in-progress') return d.isSolved === 'in-progress';
- return d.isSolved === 'solved';
- });
- const isLoadingMore = isLoading || (size > 0 && data && typeof data[size - 1] === "undefined");
- const lastPage = data ? data[data.length - 1] : null;
- const isReachingEnd =
- data &&
- (Array.isArray(lastPage)
- ? lastPage.length < PAGE_SIZE
- : !lastPage?.hasMore);
-
- const { ref: loadMoreRef, inView } = useInView();
-
- useEffect(() => {
- if (inView && !isReachingEnd && !isLoadingMore) {
- setSize(size + 1);
- }
- }, [inView, isReachingEnd, isLoadingMore]);
-
- const emptyMessages = [
- { headline: "Every legendary thread", accent: "starts with one question.", sub: "That question could be yours. Post it before someone else does." },
- { headline: "Silence is just", accent: "an unanswered question.", sub: "Someone here knows exactly what you're stuck on. But they're waiting for you to ask." },
- { headline: "Your doubt could be", accent: "the spark this board needs.", sub: "The most upvoted posts were once just a nervous first question. Go for it." },
- { headline: "Nobody's been brave", accent: "enough to ask yet.", sub: "Asking isn't weakness, it's how the smartest people in the room got there." },
- { headline: "This space is waiting", accent: "for someone like you.", sub: "You showed up. That's already more than most. Now ask what brought you here." },
- { headline: "Zero doubts.", accent: "Infinite opportunity.", sub: "Clean slate. No noise. Just you, your question, and a community ready to answer." },
- { headline: "The best communities", accent: "start with one voice.", sub: "This board needs its first voice. Might as well be the one who actually showed up." },
- { headline: "Still reading this?", accent: "That's your sign to post.", sub: "You already know what you want to ask. Stop overthinking — just type it out." },
- { headline: "You're literally", accent: "the first one here.", sub: "Pioneer energy. The ones who post first always get the most answers." },
- { headline: "What's the one thing", accent: "you've been afraid to ask?", sub: "Anonymous means nobody knows it's you. So ask the thing you'd never ask in class." },
- ];
- const [randomMessage, setRandomMessage] = useState(emptyMessages[0]);
-
- useEffect(() => {
- setRandomMessage(
- emptyMessages[Math.floor(Math.random() * emptyMessages.length)]
- );
- }, [filter, customFilter]);
-
- useEffect(() => {
- mutate();
- }, [filter, appliedCustomFilter]);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
setSearchVal(e.target.value)}
- className="w-full bg-white dark:bg-zinc-900 border border-slate-200 dark:border-zinc-800 rounded-xl py-4 pl-12 pr-6 text-sm font-medium text-slate-900 dark:text-white placeholder:text-slate-400 dark:placeholder:text-zinc-600 focus:outline-none focus:border-blue-500/50 transition-all shadow-sm"
- />
-
-
-
-
-
- Filter:
-
- {(() => {
- const filtersList = ["All", "Math", "Science", "Physics", "Chemistry", "Programming", "Others"];
- if (isSignedIn) {
- filtersList.push("Bookmarked");
- }
- return filtersList;
- })().map((f) => (
-
{
- setFilter(f);
- if (f !== "Others") {
- setCustomFilter("");
- setAppliedCustomFilter("");
- setIsOthersActive(false);
- } else {
- setIsOthersActive(true);
- }
- }}
- className={`px-5 py-2 rounded-xl text-[11px] font-bold uppercase tracking-wider transition-all duration-300 border shrink-0 flex items-center gap-1.5 ${
- filter === f
- ? f === "Bookmarked"
- ? "bg-blue-500/20 border-blue-500/30 text-blue-500 dark:text-blue-400 shadow-lg shadow-blue-500/5"
- : "bg-blue-600 border-blue-500 text-white shadow-lg shadow-blue-600/10"
- : "bg-white dark:bg-zinc-950/20 border-slate-200 dark:border-zinc-900 text-slate-500 dark:text-zinc-400 hover:bg-slate-50 dark:hover:bg-zinc-900/40"
- }`}
- >
- {f === "Bookmarked" && (
-
- )}
- {f}
-
- ))}
-
- {filter === "Others" && (
-
- setCustomFilter(e.target.value)}
- onKeyDown={(e) => {
- if (e.key === 'Enter') setAppliedCustomFilter(customFilter);
- }}
- className="bg-white dark:bg-zinc-900 border border-slate-200 dark:border-zinc-800 rounded-xl px-3 py-2 text-[11px] font-medium text-slate-900 dark:text-white placeholder:text-slate-400 dark:placeholder:text-zinc-600 focus:outline-none focus:border-blue-500 transition-all w-36"
- />
- setAppliedCustomFilter(customFilter)}
- className="px-3 py-2 bg-blue-500/10 text-blue-600 dark:text-blue-400 hover:bg-blue-600 hover:text-white border border-blue-500/20 rounded-xl text-[10px] font-bold uppercase tracking-wider transition-all"
- >
- Apply
-
-
- )}
-
-
- setTagFilter(e.target.value)}
- onKeyDown={(e) => {
- if (e.key === "Enter") fetchDoubts();
- }}
- className="bg-white dark:bg-zinc-900 border border-slate-200 dark:border-zinc-800 rounded-xl px-3 py-2 text-[11px] font-medium text-slate-900 dark:text-white placeholder:text-slate-400 dark:placeholder:text-zinc-600 focus:outline-none focus:border-blue-500 transition-all w-36"
- />
-
- Tag
-
-
-
-
-
-
-
-
- Status:
-
- {([
- { key: 'all', label: 'All', active: "bg-blue-600 border-blue-500 text-white shadow-lg shadow-blue-600/10" },
- { key: 'unsolved', label: 'Unsolved', active: "bg-red-500/10 border-red-500/20 text-red-600 dark:text-red-400" },
- { key: 'in-progress', label: 'In Progress', active: "bg-amber-500/10 border-amber-500/20 text-amber-600 dark:text-amber-400" },
- { key: 'solved', label: 'Solved', active: "bg-emerald-500/10 border-emerald-500/20 text-emerald-600 dark:text-emerald-400" },
- ] as const).map((s) => (
-
setStatusFilter(s.key)}
- className={`px-4 py-2 rounded-xl text-[11px] font-bold uppercase tracking-wider transition-all duration-300 border shrink-0 ${
- statusFilter === s.key
- ? s.active
- : "bg-white dark:bg-zinc-950/20 border-slate-200 dark:border-zinc-900 text-slate-500 dark:text-zinc-400 hover:bg-slate-50 dark:hover:bg-zinc-900/40"
- }`}
- >
- {s.label}
-
- ))}
-
-
-
- {isLoading && doubts.length === 0 ? (
-
-
-
Syncing with community...
-
- ) : filteredDoubts.length > 0 ? (
-
-
- {filteredDoubts.map((doubt: any, index: number) => (
- mutate()} />
- ))}
-
-
- {isLoadingMore && }
-
-
- ) : doubts.length > 0 ? (
-
-
- No doubts matching this status filter.
-
-
setStatusFilter('all')}
- className="px-5 py-2 bg-white dark:bg-zinc-900 text-slate-600 dark:text-zinc-400 hover:bg-blue-600 hover:text-white border border-slate-200 dark:border-zinc-800 rounded-xl text-[11px] font-bold uppercase tracking-wider transition-all duration-300 shadow-sm"
- >
- Show all
-
-
- ) : (
-
-
-
-
-
- {searchQuery ? (
-
-
-
- ) : (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
-
-
-
- {searchQuery
- ? "No matching doubts"
- : filter === "Bookmarked"
- ? "No bookmarked doubts yet"
- : randomMessage.headline}{" "}
-
- {searchQuery ? "" : filter === "Bookmarked" ? "" : randomMessage.accent}
-
-
-
- {searchQuery
- ? `We couldn't find any doubts matching "${searchQuery}". Try a different keyword or subject.`
- : filter === "Bookmarked"
- ? "Save important doubts by clicking the bookmark icon on any doubt card to view them here later."
- : filter === "All"
- ? randomMessage.sub
- : `${filter} is wide open. Drop a doubt, and watch your classmates rally around it.`}
-
-
-
-
- {searchQuery ? (
-
setSearchVal("")}
- className="flex items-center gap-3 px-6 py-3.5 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-bold uppercase tracking-wider text-xs transition-all duration-300 shadow-md shadow-blue-600/10 active:scale-[0.98]"
- >
- Clear Search
-
- ) : filter === "Bookmarked" ? (
-
setFilter("All")}
- className="group flex items-center gap-3 px-6 py-3.5 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-bold uppercase tracking-wider text-xs transition-all duration-300 shadow-md shadow-blue-600/10 active:scale-[0.98]"
- >
- Explore public doubts
-
- ) : (
-
setIsAskModalOpen(true)}
- className="group flex items-center gap-3 px-6 py-3.5 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-bold uppercase tracking-wider text-xs transition-all duration-300 shadow-md shadow-blue-600/10 active:scale-[0.98]"
- >
-
- Be the first to ask
-
- )}
-
Anonymous · No login needed
-
-
- )}
-
- {isAskModalOpen && (
-
setIsAskModalOpen(false)}
- onSuccess={() => {
- setIsAskModalOpen(false);
- mutate();
- }}
- />
- )}
-
- );
-}
\ No newline at end of file
+ .catch(err => console.error(err))
\ No newline at end of file