Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

# cursor
.cursor
14 changes: 12 additions & 2 deletions app/c/[cid]/add-problem/problem-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { useState } from "react";
import type { Collection, Subject } from "@prisma/client";
import ClickToEdit from "@/components/click-to-edit";
import Label from "@/components/label";
import AimeInput from "./aime-input";
import AimeInput from "@/components/aime-input";
import SubmitButton from "@/components/submit-button";
import { addProblem } from "./actions";
import BackButton from "@/components/back-button";
import { wrapAction } from "@/lib/server-actions";
import IntegerInput from "@/components/integer-input";

interface SubjectSelectElement extends HTMLSelectElement {
value: Subject;
Expand Down Expand Up @@ -80,7 +81,16 @@ export default function ProblemForm({
</div>
);
} else if (collection.answerFormat === "Integer") {
// TODO
answerInput = (
<div>
{answerLabel}
<IntegerInput
value={answer}
onValueChange={setAnswer}
required={collection.requireAnswer}
/>
</div>
);
} else if (collection.answerFormat === "AIME") {
answerInput = (
<div>
Expand Down
2 changes: 1 addition & 1 deletion app/c/[cid]/p/[pid]/problem-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ export default function ProblemPage(props: PropsWithFilter) {
<hr className="my-8" />
<Testsolve
problem={problem}
solveAttempt={solveAttempt}
deadline={deadline}
answerFormat={collection.answerFormat}
/>
</div>
);
Expand Down
26 changes: 18 additions & 8 deletions app/c/[cid]/p/[pid]/testsolve.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@

import { useRouter } from "next/navigation";
import CountdownTimer from "./countdown-timer";
import AimeInput from "../../add-problem/aime-input";
import AimeInput from "@/components/aime-input";
import { useState } from "react";
import Label from "@/components/label";
import { SolveAttempt } from "@prisma/client";
import { AnswerFormat } from "@prisma/client";
import { ProblemProps } from "./types";
import SubmitButton from "@/components/submit-button";
import { giveUpTestsolve, submitTestsolve } from "./actions";
import { wrapAction } from "@/lib/server-actions";
import IntegerInput from "@/components/integer-input";

// TODO: fix loading spinners for the two submit buttons. Probably need to show a single loading spinner outside of the buttons. That also lets us keep the same button text and width
export default function Testsolve({
problem,
deadline,
answerFormat,
}: {
problem: ProblemProps;
solveAttempt: SolveAttempt;
deadline: Date;
answerFormat: AnswerFormat;
}) {
const router = useRouter();
const [answer, setAnswer] = useState("");
Expand All @@ -45,11 +47,19 @@ export default function Testsolve({
>
<Label text="ANSWER" />
<div className="mb-3">
<AimeInput
value={answer}
onValueChange={(newValue: string) => setAnswer(newValue)}
required
/>
{answerFormat === "AIME" ? (
<AimeInput
value={answer}
onValueChange={(newValue: string) => setAnswer(newValue)}
required={true}
/>
) : (
<IntegerInput
value={answer}
onValueChange={(newValue: string) => setAnswer(newValue)}
required={true}
/>
)}
</div>
<div className="my-4 flex items-center gap-x-6">
<SubmitButton className="flex-grow-0">Submit</SubmitButton>
Expand Down
1 change: 1 addition & 0 deletions app/c/[cid]/p/[pid]/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const collectionSelect = {
name: true,
showAuthors: true,
requireTestsolve: true,
answerFormat: true,
};
const collectionProps = Prisma.validator<Prisma.CollectionDefaultArgs>()({
select: collectionSelect,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ interface AimeInputProps {
required: boolean;
}

const AimeInput: React.FC<AimeInputProps> = ({
value,
onValueChange,
required,
}) => {
const AimeInput = ({ value, onValueChange, required }: AimeInputProps) => {
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
let newValue = e.target.value;
if (/^\d{1,3}$/.test(newValue) || newValue === "") {
Expand Down
41 changes: 41 additions & 0 deletions components/integer-input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { ChangeEvent } from "react";

interface IntegerInputProps {
value: string;
onValueChange: (newValue: string) => void;
required: boolean;
}

const IntegerInput = ({
value,
onValueChange,
required,
}: IntegerInputProps) => {
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
let newValue = e.target.value;
// Allow empty string, optional minus sign, followed by digits
if (/^-?\d*$/.test(newValue)) {
// Convert to number and back to string to normalize format
// (e.g. remove leading zeros, but keep minus sign)
newValue =
newValue === "" || newValue === "-"
? newValue
: String(Number(newValue));
onValueChange(newValue);
}
};

return (
<input
name="answer"
type="text"
value={value}
onChange={handleChange}
placeholder="Enter an integer"
className="w-full rounded-md bg-slate-50"
required={required}
/>
);
};

export default IntegerInput;