Skip to content
Open
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
141 changes: 1 addition & 140 deletions src/app/(routes)/public-rooms/[subject]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,143 +23,4 @@
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 (
<div className="p-4 md:p-8 space-y-8 max-w-5xl mx-auto pb-24 text-slate-900 dark:text-zinc-100 bg-white dark:bg-black min-h-screen transition-colors duration-500 relative overflow-hidden">
<div className="absolute top-0 left-0 w-[500px] h-[500px] bg-blue-500/10 dark:from-blue-500/5 blur-[120px] rounded-full -translate-x-1/2 -translate-y-1/2 pointer-events-none z-0" />



<header className="flex flex-col md:flex-row md:items-end justify-between gap-6 pb-6 border-b border-slate-100 dark:border-zinc-900/60 relative z-10">
<div className="space-y-2">
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-black text-slate-900 dark:text-white tracking-tight capitalize">
{subject} Room
</h1>
<p className="text-slate-500 dark:text-zinc-400 text-sm font-medium leading-relaxed max-w-2xl">
Ask and answer doubts anonymously in the <span className="text-blue-600 dark:text-blue-400 font-bold capitalize">{subject}</span> community.
</p>
</div>
<button
onClick={() => setIsAskModalOpen(true)}
aria-label="Ask a Doubt"
className="flex items-center gap-3 px-6 py-4 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-bold uppercase tracking-wider text-xs transition-all duration-300 shadow-lg shadow-blue-600/10 active:scale-[0.98] shrink-0"
>
<Plus className="w-5 h-5" />
Ask a Doubt
</button>
</header>

<div className="flex justify-end relative z-10">
<DoubtSortSelect value={sort} onValueChange={updateSort} />
</div>

{isLoading && doubts.length === 0 ? (
<div className="flex flex-col items-center justify-center py-20 space-y-4 relative z-10">
<Loader2 className="w-8 h-8 text-blue-500 animate-spin" />
<p className="text-slate-400 dark:text-zinc-500 font-bold uppercase tracking-wider text-xs">Loading Doubts...</p>
</div>
) : doubts.length > 0 ? (
<div className="relative z-10">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{doubts.map((doubt: any, index: number) => (
<DoubtCard key={`${doubt.id}-${index}`} doubt={doubt} onUpdate={() => mutate()} />
))}
</div>
<div ref={loadMoreRef} className="py-8 flex justify-center">
{isLoadingMore && <Loader2 className="w-8 h-8 text-blue-500 animate-spin" />}
</div>
</div>
) : (
<div className="flex flex-col items-center justify-center py-20 bg-slate-50/30 dark:bg-zinc-950/10 border border-dashed border-slate-200 dark:border-zinc-900 rounded-2xl text-center px-6 shadow-sm relative z-10">
<div className="w-16 h-16 bg-white dark:bg-zinc-900 border border-slate-200 dark:border-zinc-800 rounded-xl flex items-center justify-center mb-6 shadow-sm">
<MessageSquare className="w-7 h-7 text-blue-500" />
</div>
<h2 className="text-xl font-bold text-slate-900 dark:text-white tracking-tight mb-2">No doubts yet!</h2>
<p className="text-slate-500 dark:text-zinc-400 max-w-sm mx-auto font-medium text-xs leading-relaxed mb-6">
Be the first to start a conversation in the {subject} room. All posts are anonymous.
</p>
<button
onClick={() => 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
</button>
</div>
)}

{isAskModalOpen && (
<AskDoubt
defaultSubject={subject}
isOpen={isAskModalOpen}
onClose={() => setIsAskModalOpen(false)}
onSuccess={() => {
setIsAskModalOpen(false);
mutate();
}}
/>
)}
</div>
);
}
.catch(err => console.error(err))

Check failure on line 26 in src/app/(routes)/public-rooms/[subject]/page.tsx

View workflow job for this annotation

GitHub Actions / TypeScript Check

'}' expected.

Check failure on line 26 in src/app/(routes)/public-rooms/[subject]/page.tsx

View workflow job for this annotation

GitHub Actions / TypeScript Check

';' expected.

Check failure on line 26 in src/app/(routes)/public-rooms/[subject]/page.tsx

View workflow job for this annotation

GitHub Actions / TypeScript Check

')' expected.

Check failure on line 26 in src/app/(routes)/public-rooms/[subject]/page.tsx

View workflow job for this annotation

GitHub Actions / TypeScript Check

'try' expected.

Check failure on line 26 in src/app/(routes)/public-rooms/[subject]/page.tsx

View workflow job for this annotation

GitHub Actions / TypeScript Check

Declaration or statement expected.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The added rejection handler only logs the error and returns undefined, converting failed fetches into fulfilled promises. Consumers such as SWR will therefore not receive an error state and may treat the missing response as valid data; rethrow the error after logging or return a rejected promise. [api mismatch]

Severity Level: Critical 🚨
- ❌ Public-room page currently fails parsing during builds.
- ❌ Corrected chaining hides failed public-room fetches from SWR.
- ⚠️ Failed requests produce undefined data instead of error state.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/app/(routes)/public-rooms/[subject]/page.tsx
**Line:** 26:26
**Comment:**
	*Api Mismatch: The added rejection handler only logs the error and returns `undefined`, converting failed fetches into fulfilled promises. Consumers such as SWR will therefore not receive an error state and may treat the missing response as valid data; rethrow the error after logging or return a rejected promise.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files matching public rooms:"
fd -a 'page\.tsx$' . | rg 'public-rooms|public.*rooms' || true

echo
echo "Inspect target snippets:"
for f in 'src/app/(routes)/public-rooms/[subject]/page.tsx' 'src/app/(routes)/public-rooms/page.tsx'; do
  if [ -f "$f" ]; then
    echo "--- $f line count ---"
    wc -l "$f"
    echo "--- relevant lines ---"
    nl -ba "$f" | sed -n '1,110p'
  else
    echo "MISSING: $f"
  fi
done

echo
echo "Search for detached catch after semicolon around public-rooms files:"
rg -n -C 3 '\.catch\s*\(' 'src/app/(routes)/public-rooms' || true

Repository: knoxiboy/DoubtDesk

Length of output: 521


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Inspect target files with line numbers:"
for f in 'src/app/(routes)/public-rooms/[subject]/page.tsx' 'src/app/(routes)/public-rooms/page.tsx'; do
  if [ -f "$f" ]; then
    echo "--- $f ($(wc -l < "$f") lines) ---"
    awk '{printf "%5d  %s\n", NR, $0}' "$f"
  else
    echo "MISSING: $f"
  fi
done

echo
echo "Search for catch handlers:"
rg -n -C 3 '\.catch\s*\(' 'src/app/(routes)/public-rooms' || true

echo
echo "Parse syntax check with Node:"
node - <<'JS'
const fs = require('fs');
const files = [
  'src/app/(routes)/public-rooms/[subject]/page.tsx',
  'src/app/(routes)/public-rooms/page.tsx'
];
for (const file of files) {
  if (!fs.existsSync(file)) {
    console.log(file + ' missing');
    continue;
  }
  try {
    new Function(fs.readFileSync(file, 'utf8'));
    console.log(file + ' parses');
  } catch (err) {
    console.log(file + ' syntax error:', err.message);
  }
}
JS

Repository: knoxiboy/DoubtDesk

Length of output: 5751


Don’t detach .catch() from the public-room fetchers.

Both fetcher definitions end the promise expression before .catch(...) is attached, so these files fail to compile. Chain the catch from the fetcher and rethrow/log errors correctly for SWR error handling.

🧰 Tools
🪛 Biome (2.5.5)

[error] 26-26: Expected a statement but instead found '.catch(err => console.error(err))'.

(parse)


[error] 26-26: expected } but instead the file ends

(parse)

🪛 GitHub Check: TypeScript Check

[failure] 26-26:
'}' expected.


[failure] 26-26:
';' expected.


[failure] 26-26:
')' expected.


[failure] 26-26:
'try' expected.


[failure] 26-26:
Declaration or statement expected.

📍 Affects 2 files
  • src/app/(routes)/public-rooms/[subject]/page.tsx#L26-L26 (this comment)
  • src/app/(routes)/public-rooms/page.tsx#L66-L66
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`(routes)/public-rooms/[subject]/page.tsx at line 26, Attach .catch()
directly to both public-room fetcher promise expressions in
src/app/(routes)/public-rooms/[subject]/page.tsx:26-26 and
src/app/(routes)/public-rooms/page.tsx:66-66. Ensure each fetcher logs the error
and rethrows it so SWR receives the rejected promise for error handling.

Source: Linters/SAST tools

Loading
Loading