difficulty filters and clickable badges
This commit is contained in:
@@ -39,12 +39,15 @@ export default async function QuestionDetailPage({
|
||||
<div>
|
||||
<div className="flex items-start justify-between gap-4 mb-4">
|
||||
<h1 className="text-3xl font-bold">{question.title}</h1>
|
||||
<Badge
|
||||
variant={getDifficultyVariant(question.difficulty)}
|
||||
aria-label={getDifficultyLabel(question.difficulty)}
|
||||
>
|
||||
{capitalize(question.difficulty)}
|
||||
</Badge>
|
||||
<Link href={`/questions?difficulty=${question.difficulty}`}>
|
||||
<Badge
|
||||
variant={getDifficultyVariant(question.difficulty)}
|
||||
aria-label={getDifficultyLabel(question.difficulty)}
|
||||
className="cursor-pointer hover:opacity-80"
|
||||
>
|
||||
{capitalize(question.difficulty)}
|
||||
</Badge>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-2 mb-4">
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { getQuestions, getCategories, getPatterns } from "@/lib/api";
|
||||
import type { CategoryListResponse, PatternListResponse, Difficulty } from "@/types";
|
||||
import { QuestionCard } from "@/components/questions/question-card";
|
||||
import { QuestionFilters } from "@/components/questions/question-filters";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { getDifficultyVariant, capitalize } from "@/lib/utils";
|
||||
import Link from "next/link";
|
||||
|
||||
interface SearchParams {
|
||||
@@ -16,8 +20,8 @@ export default async function QuestionsPage({
|
||||
searchParams: Promise<SearchParams>;
|
||||
}) {
|
||||
const params = await searchParams;
|
||||
const [questionsResponse, categoriesResponse, patternsResponse] =
|
||||
await Promise.all([
|
||||
const [questionsResult, categoriesResult, patternsResult] =
|
||||
await Promise.allSettled([
|
||||
getQuestions({
|
||||
difficulty: params.difficulty,
|
||||
category: params.category,
|
||||
@@ -29,7 +33,28 @@ export default async function QuestionsPage({
|
||||
getPatterns(),
|
||||
]);
|
||||
|
||||
const difficulties = ["easy", "medium", "hard"];
|
||||
if (questionsResult.status === "rejected") {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<h1 className="text-3xl font-bold">Questions</h1>
|
||||
<p className="text-[var(--muted-foreground)]">
|
||||
Unable to load questions. Please try again later.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const questionsResponse = questionsResult.value;
|
||||
const categoriesResponse: CategoryListResponse =
|
||||
categoriesResult.status === "fulfilled"
|
||||
? categoriesResult.value
|
||||
: { items: [] };
|
||||
const patternsResponse: PatternListResponse =
|
||||
patternsResult.status === "fulfilled"
|
||||
? patternsResult.value
|
||||
: { items: [] };
|
||||
|
||||
const difficulties: Difficulty[] = ["easy", "medium", "hard"];
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -41,83 +66,35 @@ export default async function QuestionsPage({
|
||||
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 href="/questions">
|
||||
<Badge
|
||||
variant={!params.difficulty ? "default" : "outline"}
|
||||
className="cursor-pointer hover:opacity-80"
|
||||
>
|
||||
All
|
||||
</Badge>
|
||||
</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 key={d} href={`/questions?difficulty=${d}`}>
|
||||
<Badge
|
||||
variant={
|
||||
params.difficulty === d ? getDifficultyVariant(d) : "outline"
|
||||
}
|
||||
className="cursor-pointer hover:opacity-80"
|
||||
>
|
||||
{capitalize(d)}
|
||||
</Badge>
|
||||
</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>
|
||||
<QuestionFilters
|
||||
categories={categoriesResponse.items}
|
||||
patterns={patternsResponse.items}
|
||||
currentCategory={params.category}
|
||||
currentPattern={params.pattern}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-[var(--muted-foreground)]">
|
||||
|
||||
Reference in New Issue
Block a user