working Problems

This commit is contained in:
2026-02-07 16:08:22 +01:00
parent 969500f5a4
commit 4e92010bfe
6 changed files with 102 additions and 125 deletions
+26 -30
View File
@@ -1,23 +1,18 @@
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Clock, Zap, Users } from "lucide-react"; import { Problem } from "@/modules/problems/types";
import { Clock, Zap, Users, Code } from "lucide-react";
interface ProblemCardProps {
name: string;
difficulty: "easy" | "medium" | "hard";
tags: string[];
bestTime?: string;
attempts: number;
index?: number;
}
const ProblemCard = ({ const ProblemCard = ({
name, problem,
difficulty,
tags,
bestTime,
attempts,
index = 0, index = 0,
}: ProblemCardProps) => { bestTime,
attempts = 0,
}: {
problem: Problem;
index?: number;
bestTime?: string;
attempts?: number;
}) => {
const difficultyStyles = { const difficultyStyles = {
easy: "diff-easy", easy: "diff-easy",
medium: "diff-medium", medium: "diff-medium",
@@ -46,29 +41,30 @@ const ProblemCard = ({
{/* Header */} {/* Header */}
<div className="flex items-start justify-between mb-3"> <div className="flex items-start justify-between mb-3">
<h3 className="font-semibold text-foreground group-hover:text-primary transition-colors"> <h3 className="font-semibold text-foreground group-hover:text-primary transition-colors">
{name} {problem.title}
</h3> </h3>
<span <span
className={`px-2 py-1 rounded-md text-xs font-medium ${difficultyStyles[difficulty]}`} className={`px-2 py-1 rounded-md text-xs font-medium ${
difficultyStyles[problem.difficulty]
}`}
> >
{difficultyLabels[difficulty]} {difficultyLabels[problem.difficulty]}
</span> </span>
</div> </div>
{/* Tags */} {/* Tags / Meta */}
<div className="flex flex-wrap gap-2 mb-4"> <div className="flex flex-wrap gap-2 mb-4 text-xs text-muted-foreground">
{tags.map((tag) => ( {problem.language && (
<span <span className="px-2 py-1 rounded-md bg-secondary">
key={tag} <Code className="w-3 h-3 inline-block mr-1" /> {problem.language}
className="px-2 py-1 rounded-md bg-secondary text-muted-foreground text-xs"
>
{tag}
</span> </span>
))} )}
</div> </div>
{/* Spacer */} {/* Description */}
<div className="flex-1" /> <p className="text-sm text-muted-foreground flex-1">
{problem.description}
</p>
{/* Stats + Action */} {/* Stats + Action */}
<div className="flex items-center justify-between mt-4 text-sm text-muted-foreground"> <div className="flex items-center justify-between mt-4 text-sm text-muted-foreground">
+3 -1
View File
@@ -14,6 +14,8 @@ import { getProblems } from "@/modules/problems/actions";
export default function Problems() { export default function Problems() {
const [problems, problemsLoaded, problemsError] = useAction(getProblems); const [problems, problemsLoaded, problemsError] = useAction(getProblems);
console.log(problems);
const [viewMode, setViewMode] = useState<"grid" | "list">("grid"); const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
const difficulties = ["All", "Easy", "Medium", "Hard"]; const difficulties = ["All", "Easy", "Medium", "Hard"];
@@ -84,7 +86,7 @@ export default function Problems() {
> >
{problems && {problems &&
problems.map((problem, i) => ( problems.map((problem, i) => (
<ProblemCard key={problem.name} {...problem} index={i} /> <ProblemCard key={problem.title} index={i} problem={problem} />
))} ))}
</div> </div>
</div> </div>
+8 -4
View File
@@ -45,11 +45,15 @@ export default function Run() {
<div className="flex-1"> <div className="flex-1">
<ProblemCard <ProblemCard
name="Idk"
difficulty="hard"
tags={[]}
attempts={0}
index={4} index={4}
problem={{
id: "fix-auth-callback",
title: "Fix the Broken Auth Callback",
description:
"Users can log in with OAuth, but sessions aren't persisted. Fix it.",
language: "typescript",
difficulty: "easy",
}}
/> />
</div> </div>
</div> </div>
+1 -86
View File
@@ -4,90 +4,5 @@ import * as Core from "./core";
import { Problem } from "./types"; import { Problem } from "./types";
export async function getProblems(): Promise<Problem[]> { export async function getProblems(): Promise<Problem[]> {
return [ return await Core.getProblems();
{
name: "Two Sum Dash",
difficulty: "easy" as const,
tags: ["arrays", "hash-map"],
bestTime: "0:42",
attempts: 12453,
},
{
name: "Binary Sprint",
difficulty: "easy" as const,
tags: ["binary-search"],
bestTime: "0:38",
attempts: 8921,
},
{
name: "Linked List Rush",
difficulty: "medium" as const,
tags: ["linked-list", "pointers"],
bestTime: "1:24",
attempts: 6234,
},
{
name: "Tree Traverse Blitz",
difficulty: "medium" as const,
tags: ["trees", "recursion"],
bestTime: "2:01",
attempts: 5102,
},
{
name: "DP Gauntlet",
difficulty: "hard" as const,
tags: ["dynamic-programming"],
bestTime: "4:32",
attempts: 2341,
},
{
name: "Graph Navigator",
difficulty: "hard" as const,
tags: ["graphs", "bfs", "dfs"],
bestTime: "3:45",
attempts: 3456,
},
{
name: "String Scramble",
difficulty: "easy" as const,
tags: ["strings", "manipulation"],
bestTime: "0:55",
attempts: 9876,
},
{
name: "Stack Overflow",
difficulty: "medium" as const,
tags: ["stacks", "queues"],
bestTime: "1:42",
attempts: 4567,
},
{
name: "Heap Hero",
difficulty: "hard" as const,
tags: ["heaps", "priority-queue"],
bestTime: "3:21",
attempts: 1890,
},
{
name: "Sliding Window Slam",
difficulty: "medium" as const,
tags: ["sliding-window", "arrays"],
bestTime: "1:56",
attempts: 5678,
},
{
name: "Trie Triumph",
difficulty: "hard" as const,
tags: ["trie", "strings"],
bestTime: "4:12",
attempts: 1234,
},
{
name: "Backtrack Blaster",
difficulty: "hard" as const,
tags: ["backtracking", "recursion"],
bestTime: "5:01",
attempts: 987,
},
];
} }
+43
View File
@@ -1,3 +1,46 @@
"use server"; "use server";
import "server-only"; import "server-only";
import { ProblemDefinition } from "./types";
const problems: ProblemDefinition[] = [
{
id: "fix-auth-callback",
title: "Fix the Broken Auth Callback",
description:
"Users can log in with OAuth, but sessions aren't persisted. Fix it.",
language: "typescript",
difficulty: "easy",
validate100: () => true,
validateAny: () => true,
},
{
id: "fix-prod-build",
title: "Patch a Failing Production Build",
description:
"Production build fails while development works. Fix the build.",
language: "javascript",
difficulty: "easy",
validate100: () => true,
validateAny: () => true,
},
{
id: "add-user-profile-endpoint",
title: "Implement Missing API Endpoint",
description: "The frontend expects `/api/me`. Implement it correctly.",
language: "go",
difficulty: "easy",
validate100: () => true,
validateAny: () => true,
},
];
export async function getProblems() {
return problems.map((def) => ({
id: def.id,
title: def.title,
description: def.description,
difficulty: def.difficulty,
language: def.language,
}));
}
+21 -4
View File
@@ -1,7 +1,24 @@
export type ProblemValidator = (submission: any) => boolean;
export interface Problem { export interface Problem {
name: string; id: string;
title: string;
description: string;
difficulty: "easy" | "medium" | "hard"; difficulty: "easy" | "medium" | "hard";
tags: string[]; language:
bestTime?: string; | "rust"
attempts: number; | "go"
| "java"
| "javascript"
| "typescript"
| "python"
| null;
}
export interface ProblemDefinition extends Problem {
/* Any% validator */
validateAny: ProblemValidator;
/* 100% validator */
validate100: ProblemValidator;
metadata?: Record<string, any>; // optional extra info like time limits, refs
} }