Skip to content
Merged
23 changes: 8 additions & 15 deletions src/app/frq-feedback/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

"use client";

import FRQFeedbackRenderer from "@/components/frq/feedbackRenderer";
Expand All @@ -18,22 +17,18 @@ const Page = () => {
const fetchFeedback = async () => {
setStatus("loading");
try {
const docRef = doc(
db,
"frq-feedback",
frqId
);
const docRef = doc(db, "frq-feedback", frqId);
const docSnap = await getDoc(docRef);

if (docSnap.exists()) {
setStatus("found");
} else {
setStatus("not-found");
}
} catch (error: unknown) {
console.error("Error fetching FRQ feedback:", error);
setStatus("not-found");
}
} catch (error: unknown) {
console.error("Error fetching FRQ feedback:", error);
setStatus("not-found");
}
};

void fetchFeedback();
Expand All @@ -44,11 +39,9 @@ const Page = () => {
}

return (
<div className="px-8 py-12">
<FRQFeedbackRenderer
feedbackFound={status === "found"}
/>
</div>
<div>
<FRQFeedbackRenderer />
</div>
);
};

Expand Down
105 changes: 105 additions & 0 deletions src/components/frq/feedback/dropdownContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"use client";

import { ChevronDown, ChevronRight } from "lucide-react";
import { RenderContent } from "@/components/article-creator/custom_questions/RenderAdvancedTextbox";
import RubricCriteriaRow from "./rubricCriteriaRow";
import type { FRQPart, FRQPartFeedback, ResponseAnswer } from "./types";
import { Textarea } from "@/components/ui/textarea";

interface FeedbackSectionProps {
part: FRQPart;
label: string;
answer?: ResponseAnswer;
partFeedback?: FRQPartFeedback;
isOpen: boolean;
onToggle: () => void;
onFeedbackChange: (feedback: string) => void;
onPointsChange: (criterionId: string, points: number) => void;
}

export default function FeedbackSection({
part,
label,
answer,
partFeedback,
isOpen,
onToggle,
onFeedbackChange,
onPointsChange,
}: FeedbackSectionProps) {
const pointsEarned =
partFeedback?.gradingCriteria.reduce(
(total, criterion) => total + criterion.points,
0,
) ?? 0;

const pointsPossible = part.gradingCriteria.reduce(
(total, criterion) => total + criterion.points,
0,
);

return (
<div>
<button
type="button"
onClick={onToggle}
className="flex w-full items-center bg-gray-100"
>
<span className="bg-black px-3 py-2 font-bold text-white">{label}</span>

<p className="flex-1 px-3 text-left font-bold">
{pointsEarned}/{pointsPossible} Points
</p>

<span className="px-3">
{isOpen ? (
<ChevronDown className="size-5" />
) : (
<ChevronRight className="size-5" />
)}
</span>
</button>

{isOpen && (
<div className="mt-4 space-y-4">
<RenderContent content={part.prompt} origin="question" />

<div className="rounded-md border border-gray-400 p-3">
<RenderContent
content={{
value: answer?.value ?? "No response submitted.",
files: [],
}}
origin="content"
/>
</div>

<div>
{part.gradingCriteria.map((criterion) => {
const criterionScore = partFeedback?.gradingCriteria.find(
(score) => score.criterionId === criterion.id,
);

return (
<RubricCriteriaRow
key={criterion.id}
criterion={criterion}
points={criterionScore?.points ?? 0}
onPointsChange={(points) =>
onPointsChange(criterion.id, points)
}
/>
);
})}
</div>
<Textarea
value={partFeedback?.feedback ?? ""}
onChange={(event) => onFeedbackChange(event.target.value)}
placeholder="Enter feedback"
className="min-h-24 resize-y border-gray-400"
/>
</div>
)}
</div>
);
}
167 changes: 167 additions & 0 deletions src/components/frq/feedback/fallBackData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
export const fallbackFeedbackData = {
name: "AP Human Geography FRQ 1",
creatorID: "1259823594",
mostRecentEditor: "1259823594",
id: "43281",
isVisible: true,
feedback: {
id: "47231",
graderId: "964923741",
submittedAt: "2026-07-13T18:30:00Z",
questions: [
{
questionId: "53213",
feedback: "",
gradingCriteria: [
{
criterionId: "59684",
points: 3,
},
{
criterionId: "85931",
points: 1,
},
],
},
{
questionId: "53214",
feedback: "",
gradingCriteria: [
{
criterionId: "59685",
points: 1,
},
{
criterionId: "85930",
points: 1,
},
],
},
{
questionId: "63213",
feedback: "",
gradingCriteria: [
{
criterionId: "69684",
points: 3,
},
{
criterionId: "75931",
points: 0,
},
],
},
],
},
response: {
id: "47231",
userId: "3749237134",
submittedAt: "2026-07-13T18:30:00Z",
answers: [
{
questionId: "53213",
value: "1-1 Answer",
},
{
questionId: "53214",
value: "1-2 Answer",
},
{
questionId: "63213",
value: "2-1 Answer",
},
],
},
frqs: [
{
id: "12345",
name: "FRQ 1",
description: {
value:
"Choice A is incorrect. As $@x = 1$ is a vertical asymptote, the limit as the function approaches that value will not be a definite number, but some infinity. Choice B is incorrect. It is true that as the limit of a function approaches a vertical asymptote, it will approach an infinity. However, we can use simple numerical logic to guide and realize that $@\\displaystyle\\frac{0.9999}{0.9999^2 - 1}$ will be negative, since $@1^-$ indicates a quantity that is slightly smaller than 1. Choice C is correct. A vertical asymptote exists at $@x = 1$, so the one-sided limit will yield an infinite value. As $@x$ approaches $@1$ from the left of the function, the denominator approaches a very small negative value and the numerator is positive. This evaluates to a large negative number, indicating that the limit is $@-\\infty$. Choice D is incorrect. To some extent, it is true that if a limit approaches infinity, it is a case of DNE since it experiences unbounded change. HOWEVER, the convention will ALWAYS be to specify whether or not it is a $@\\pm \\infty$, which makes C a better answer.",
files: [],
},
isVisible: true,
questions: [
{
id: "53213",
name: "Question 1",
isVisible: true,
prompt: {
value: "This is a prompt for frq 1 question 1",
files: [],
},
answerType: "text",
gradingCriteria: [
{
id: "59684",
text: "Correct Grammar",
points: 4,
},
{
id: "85931",
text: "Mentions Demographics",
points: 2,
},
],
},
{
id: "53214",
name: "Question 2",
isVisible: true,
prompt: {
value: "This is a prompt for frq 1 question 2",
files: [],
},
answerType: "text",
gradingCriteria: [
{
id: "59685",
text: "Correct Math",
points: 1,
},
{
id: "85930",
text: "Aura",
points: 2,
},
],
},
],
},
{
id: "95312",
name: "FRQ 2",
description: {
value:
"Choice A is incorrect. As $@x = 1$ is a vertical asymptote, the limit as the function approaches that value will not be a definite number, but some infinity. Choice B is incorrect. It is true that as the limit of a function approaches a vertical asymptote, it will approach an infinity. However, we can use simple numerical logic to guide and realize that $@\\displaystyle\\frac{0.9999}{0.9999^2 - 1}$ will be negative, since $@1^-$ indicates a quantity that is slightly smaller than 1. Choice C is correct. A vertical asymptote exists at $@x = 1$, so the one-sided limit will yield an infinite value. As $@x$ approaches $@1$ from the left of the function, the denominator approaches a very small negative value and the numerator is positive. This evaluates to a large negative number, indicating that the limit is $@-\\infty$.",
files: [],
},
isVisible: true,
questions: [
{
id: "63213",
name: "Question 1",
isVisible: true,
prompt: {
value: "This is a prompt for frq 2 question 1",
files: [],
},
answerType: "text",
gradingCriteria: [
{
id: "69684",
text: "Correct Grammar",
points: 4,
},
{
id: "75931",
text: "Mentions Demographics",
points: 2,
},
],
},
],
},
],
};
Loading