Skip to content
Open
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
15 changes: 12 additions & 3 deletions src/__tests__/App.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ test("creates a new question when the form is submitted", async () => {
// submit form
fireEvent.submit(screen.queryByText(/Add Question/));

// wait for the new question prompt to appear before clicking "View Questions"
await screen.findByText(/Test Prompt/g);

// view questions
fireEvent.click(screen.queryByText(/View Questions/));

Expand All @@ -75,6 +78,8 @@ test("deletes the question when the delete button is clicked", async () => {
expect(screen.queryByText(/lorem testum 1/g)).not.toBeInTheDocument();
});

import { waitFor } from "@testing-library/react";

test("updates the answer when the dropdown is changed", async () => {
const { rerender } = render(<App />);

Expand All @@ -86,9 +91,13 @@ test("updates the answer when the dropdown is changed", async () => {
target: { value: "3" },
});

expect(screen.queryAllByLabelText(/Correct Answer/)[0].value).toBe("3");
await waitFor(() => {
expect(screen.queryAllByLabelText(/Correct Answer/)[0].value).toBe("3");
});

rerender(<App />);

expect(screen.queryAllByLabelText(/Correct Answer/)[0].value).toBe("3");
});
await waitFor(() => {
expect(screen.queryAllByLabelText(/Correct Answer/)[0].value).toBe("3");
});
});
35 changes: 33 additions & 2 deletions src/components/App.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,46 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import AdminNavBar from "./AdminNavBar";
import QuestionForm from "./QuestionForm";
import QuestionList from "./QuestionList";

function App() {
const [page, setPage] = useState("List");
const [questions, setQuestions] = useState([]);

useEffect(() => {
fetch("http://localhost:4000/questions")
.then((r) => r.json())
.then(setQuestions);
}, []);

function handleAddQuestion(newQuestion) {
setQuestions((prev) => [...prev, newQuestion]);
setPage("List");
}

function handleDeleteQuestion(id) {
setQuestions((prev) => prev.filter((q) => q.id !== id));
}

function handleUpdateQuestion(updatedQuestion) {
setQuestions((prev) =>
prev.map((q) => (q.id === updatedQuestion.id ? updatedQuestion : q))
);
}


return (
<main>
<AdminNavBar onChangePage={setPage} />
{page === "Form" ? <QuestionForm /> : <QuestionList />}
{page === "Form" ? (
<QuestionForm onAddQuestion={handleAddQuestion} />
) : (
<QuestionList
questions={questions}
onDeleteQuestion={handleDeleteQuestion}
onUpdateQuestion={handleUpdateQuestion}
/>
)}
</main>
);
}
Expand Down
61 changes: 51 additions & 10 deletions src/components/QuestionForm.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import React, { useState, useEffect, useRef } from "react";

function QuestionForm(props) {
function QuestionForm({ onAddQuestion }) {
const [formData, setFormData] = useState({
prompt: "",
answer1: "",
Expand All @@ -10,16 +10,57 @@ function QuestionForm(props) {
correctIndex: 0,
});

function handleChange(event) {
setFormData({
...formData,
[event.target.name]: event.target.value,
});
const isMounted = useRef(true);

useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);

function handleChange(e) {
const { name, value } = e.target;
setFormData((prev) => ({
...prev,
[name]: value,
}));
}

function handleSubmit(event) {
event.preventDefault();
console.log(formData);
function handleSubmit(e) {
e.preventDefault();

const newQuestion = {
prompt: formData.prompt,
answers: [
formData.answer1,
formData.answer2,
formData.answer3,
formData.answer4,
],
correctIndex: parseInt(formData.correctIndex),
};

fetch("http://localhost:4000/questions", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newQuestion),
})
.then((res) => res.json())
.then((data) => {
if (isMounted.current) {
onAddQuestion(data); // Send back to App for state update
setFormData({
prompt: "",
answer1: "",
answer2: "",
answer3: "",
answer4: "",
correctIndex: 0,
});
}
});
}

return (
Expand Down
36 changes: 28 additions & 8 deletions src/components/QuestionItem.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,43 @@
import React from "react";

function QuestionItem({ question }) {
function QuestionItem({ question, onDeleteQuestion, onUpdateQuestion }) {
const { id, prompt, answers, correctIndex } = question;

const options = answers.map((answer, index) => (
<option key={index} value={index}>
{answer}
</option>
));
const handleChange = (e) => {
const newCorrectIndex = parseInt(e.target.value);

fetch(`http://localhost:4000/questions/${id}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ correctIndex: newCorrectIndex }),
})
.then((r) => r.json())
.then((updatedQuestion) => onUpdateQuestion(updatedQuestion));
};

const handleDelete = () => {
fetch(`http://localhost:4000/questions/${id}`, {
method: "DELETE",
}).then(() => onDeleteQuestion(id));
};

return (
<li>
<h4>Question {id}</h4>
<h5>Prompt: {prompt}</h5>
<label>
Correct Answer:
<select defaultValue={correctIndex}>{options}</select>
<select value={correctIndex} onChange={handleChange}>
{answers.map((answer, index) => (
<option key={index} value={index}>
{answer}
</option>
))}
</select>
</label>
<button>Delete Question</button>
<button onClick={handleDelete}>Delete Question</button>
</li>
);
}
Expand Down
14 changes: 12 additions & 2 deletions src/components/QuestionList.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import React from "react";
import QuestionItem from "./QuestionItem";

function QuestionList() {
function QuestionList({ questions, onDeleteQuestion, onUpdateQuestion }) {
return (
<section>
<h1>Quiz Questions</h1>
<ul>{/* display QuestionItem components here after fetching */}</ul>
<ul>
{questions.map((q) => (
<QuestionItem
key={q.id}
question={q}
onDeleteQuestion={onDeleteQuestion}
onUpdateQuestion={onUpdateQuestion}
/>
))}
</ul>
</section>
);
}
Expand Down