wire up pages

This commit is contained in:
2025-04-29 21:06:13 +01:00
parent 1aba5719a8
commit e6b5044256
11 changed files with 791 additions and 0 deletions
+159
View File
@@ -0,0 +1,159 @@
import { getQuestions, getCategories, getPatterns } from "@/lib/api";
import { QuestionCard } from "@/components/questions/question-card";
import Link from "next/link";
interface SearchParams {
difficulty?: string;
category?: string;
pattern?: string;
search?: string;
page?: string;
}
export default async function QuestionsPage({
searchParams,
}: {
searchParams: Promise<SearchParams>;
}) {
const params = await searchParams;
const [questionsResponse, categoriesResponse, patternsResponse] =
await Promise.all([
getQuestions({
difficulty: params.difficulty,
category: params.category,
pattern: params.pattern,
search: params.search,
page: params.page ? parseInt(params.page) : 1,
}),
getCategories(),
getPatterns(),
]);
const difficulties = ["easy", "medium", "hard"];
return (
<div className="space-y-6">
<h1 className="text-3xl font-bold">Questions</h1>
<div className="flex flex-wrap gap-4 p-4 rounded-lg bg-[var(--secondary)]">
<div className="space-y-1">
<label className="text-sm text-[var(--muted-foreground)]">
Difficulty
</label>
<div className="flex gap-2">
<Link
href="/questions"
className={`px-3 py-1 rounded text-sm ${
!params.difficulty
? "bg-[var(--primary)] text-[var(--primary-foreground)]"
: "bg-[var(--card)] hover:bg-[var(--muted)]"
}`}
>
All
</Link>
{difficulties.map((d) => (
<Link
key={d}
href={`/questions?difficulty=${d}`}
className={`px-3 py-1 rounded text-sm capitalize ${
params.difficulty === d
? "bg-[var(--primary)] text-[var(--primary-foreground)]"
: "bg-[var(--card)] hover:bg-[var(--muted)]"
}`}
>
{d}
</Link>
))}
</div>
</div>
<div className="space-y-1">
<label className="text-sm text-[var(--muted-foreground)]">
Category
</label>
<select
defaultValue={params.category || ""}
className="px-3 py-1 rounded text-sm bg-[var(--card)] border border-[var(--border)]"
onChange={(e) => {
const url = new URL(window.location.href);
if (e.target.value) {
url.searchParams.set("category", e.target.value);
} else {
url.searchParams.delete("category");
}
window.location.href = url.toString();
}}
>
<option value="">All Categories</option>
{categoriesResponse.items.map((cat) => (
<option key={cat.id} value={cat.slug}>
{cat.name} ({cat.question_count})
</option>
))}
</select>
</div>
<div className="space-y-1">
<label className="text-sm text-[var(--muted-foreground)]">
Pattern
</label>
<select
defaultValue={params.pattern || ""}
className="px-3 py-1 rounded text-sm bg-[var(--card)] border border-[var(--border)]"
onChange={(e) => {
const url = new URL(window.location.href);
if (e.target.value) {
url.searchParams.set("pattern", e.target.value);
} else {
url.searchParams.delete("pattern");
}
window.location.href = url.toString();
}}
>
<option value="">All Patterns</option>
{patternsResponse.items.map((pat) => (
<option key={pat.id} value={pat.slug}>
{pat.name} ({pat.question_count})
</option>
))}
</select>
</div>
</div>
<div className="text-sm text-[var(--muted-foreground)]">
Showing {questionsResponse.items.length} of {questionsResponse.total}{" "}
questions
</div>
<div className="grid gap-4">
{questionsResponse.items.map((question) => (
<QuestionCard key={question.id} question={question} />
))}
</div>
{questionsResponse.pages > 1 && (
<div className="flex justify-center gap-2">
{Array.from({ length: questionsResponse.pages }, (_, i) => i + 1).map(
(page) => (
<Link
key={page}
href={`/questions?page=${page}${
params.difficulty ? `&difficulty=${params.difficulty}` : ""
}${params.category ? `&category=${params.category}` : ""}${
params.pattern ? `&pattern=${params.pattern}` : ""
}`}
className={`px-3 py-1 rounded ${
page === questionsResponse.page
? "bg-[var(--primary)] text-[var(--primary-foreground)]"
: "bg-[var(--secondary)] hover:bg-[var(--muted)]"
}`}
>
{page}
</Link>
)
)}
</div>
)}
</div>
);
}