CSC/ECE 517 Spring 2026 - E2619. Student Quizzes Frontend
E2619: Student Quizzes — Design Document
Introduction
Expertiza is an educational web application collaboratively developed and maintained by students and faculty at NCSU. As an open-source project built on the Ruby on Rails platform, its code is accessible on GitHub. The platform enables students to provide peer reviews and refine their work based on feedback.
This design document describes the implementation of the E2619 Student Quizzes project, covering both the frontend (React/TypeScript) and backend (Ruby on Rails API). The project builds on the E2607 questionnaire rendering code and extends it with quiz-specific capabilities: directing students to quizzes/reviews, scoring quiz responses, specifying correct answers, and handling fill-in-the-blank questions.
Project Overview
Quizzes in Expertiza are designed to ensure that reviewers comprehend the material they
are evaluating. When an assignment includes quizzes (require_quiz = true),
submitting teams create quizzes based on their submissions. Reviewers must complete the
quizzes before reviewing to demonstrate their understanding. If a reviewer performs
poorly, their review can be discounted to maintain quality.
Previous Implementation
The prior codebase provided the data models, CRUD controllers, and UI components needed for assignments, questionnaires, and peer reviews. However, the quiz workflow was incomplete in several key ways:
Response#aggregate_questionnaire_scorecomputed scores asanswer * weightusing only the numeric answer column, with no correctness check against a stored correct answer. There was no way to distinguish a quiz response from a regular review response.- The
Itemmodel had nocorrect_answercolumn; there was nowhere to persist the expected answer for a quiz item. - The
StudentTaskmodel did not carry quiz gateway fields (require_quiz,quiz_taken,has_quiz_questionnaire,quiz_questionnaire_id), so the frontend had no structured way to know whether a student must take a quiz before reviewing. - The
Teammodel had noquiz_questionnaire_id. Quiz questionnaire ownership was expected to flow through the assignment's questionnaire list, which required instructor configuration and did not support per-team quizzes. - The
ResponseMapsControllerhad no index action that filtered out quiz maps, so the frontend could not safely list a student's review assignments without also receiving spurious self-referential quiz entries. - No
QuizResponseMapsControllerexisted; there was no endpoint to create aQuizResponseMapbefore a student started a quiz. - The questionnaire editor rendered no "Correct answer" field for any item type when the questionnaire type was set to "Quiz".
- The student task page had no "Take Quiz" button or any flow to route a student from a quiz gate to the quiz form and back to their review.
Project Goals
Based on the gaps above, this project aimed to:
- Add a
correct_answerstring column to quiz items so submitting teams can specify expected answers at quiz-creation time. - Extend
Response#aggregate_questionnaire_scoreto detect quiz responses by thereviewer_id == reviewee_idinvariant and score text/choice items from thecommentscolumn using case-insensitive equality. - Extend
StudentTaskwith four quiz gateway fields so the frontend can render the correct button (Take Quiz / Start Review) without extra API calls. - Add a
quiz_questionnaire_idcolumn toTeamso each submitting team directly owns its quiz questionnaire, enabling per-team quizzes on the same assignment. - Implement
POST /quiz_response_mapsso the frontend can create (or reuse) aQuizResponseMapbefore navigating a student to the quiz form. - Update
ResponseMapsController#indexto exclude quiz maps and include per-row quiz state. - Add a "Correct answer" row in the questionnaire editor for every quiz item type.
- Implement an instructor "Create Quiz" button on the reviewer-assignment page that opens the questionnaire editor pre-linked to the team.
- Implement a "Take Quiz" button in the student task list that calls
POST /quiz_response_mapsand navigates to the existing review form in quiz mode. - Add
GET /questions/quiz_typesso the frontend can fetch the allowed quiz item types dynamically.
Design
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ Frontend (React/TS) │
│ │
│ AssignedReviews ──→ [Take Quiz] ──→ TeammateReview │
│ │ (quiz mode) │ │
│ │ └──→ [redirect] │
│ └──→ [Start/Open Review] ──→ TeammateReview │
│ (review mode) │
│ QuestionnaireEditor ──→ correct_answer fields per type │
└──────────────────────────┬──────────────────────────────────┘
│ REST API
┌──────────────────────────┴──────────────────────────────────┐
│ Backend (Rails API) │
│ │
│ QuizResponseMapsController (POST /quiz_response_maps) │
│ ResponsesController (create / update / submit) │
│ ResponseMapsController (index — filters quiz maps) │
│ Response model (aggregate_questionnaire_score) │
│ StudentTask model (quiz gateway fields) │
└─────────────────────────────────────────────────────────────┘
UML Design
┌───────────────────────────────────────┐
│ Assignment │
├───────────────────────────────────────┤
│ +boolean require_quiz │
│ +int num_quiz_questions │
│ +has_many questionnaires (via AQ) │
└────────────────────┬──────────────────┘
│ has_many (via AQ)
▼
┌───────────────────────────────────────┐ ┌─────────────────────────────┐
│ Questionnaire │ │ Team [UPDATED] │
├───────────────────────────────────────┤ ├─────────────────────────────┤
│ +String name │ │ +int quiz_questionnaire_id │◄─── NEW
│ +String questionnaire_type │◄────│ +belongs_to │
│ ("Quiz" for quiz questionnaires) │ │ quiz_questionnaire │
│ +int min_question_score │ └─────────────────────────────┘
│ +int max_question_score │
│ +int instructor_id │
└────────────────────┬──────────────────┘
│ has_many
▼
┌───────────────────────────────────────┐
│ Item [UPDATED] │
├───────────────────────────────────────┤
│ +String txt │
│ +String question_type │
│ +int weight │
│ +String correct_answer ◄│─── NEW
│ +QUIZ_ITEM_TYPES : Array ◄│─── NEW
│ +is_quiz_item?() : boolean ◄│─── NEW
└────────────────────┬──────────────────┘
│ has_many answers
▼
┌───────────────────────────────────────┐
│ Answer │
├───────────────────────────────────────┤
│ +int item_id │
│ +int response_id │
│ +int answer │
│ +String comments (quiz answer here) │
└────────────────────┬──────────────────┘
│ belongs_to
▼
┌───────────────────────────────────────┐
│ Response [UPDATED] │
├───────────────────────────────────────┤
│ +int map_id │
│ +boolean is_submitted │
│ +int round │
│ +aggregate_questionnaire_score() ◄│─── quiz-aware: checks
│ │ reviewer_id == reviewee_id
└────────────────────┬──────────────────┘
│ belongs_to
▼
┌───────────────────────────────────────┐
│ QuizResponseMap [UPDATED] │
├───────────────────────────────────────┤
│ +int reviewer_id │
│ +int reviewee_id │
│ (reviewer_id == reviewee_id ◄│─── self-referential invariant
│ identifies quiz maps) │ distinguishes quiz from review
│ +int reviewed_object_id ◄│─── quiz questionnaire id
│ +mappings_for_reviewer() │
└───────────────────────────────────────┘
Screenshots
Take Quiz Button (Assigned Reviews)
Questionnaire Editor – Correct Answer Fields
Quiz Submission and Score Display
Changes Implemented
1) Database Schema Additions
Two new columns support the quiz feature. The correct_answer string column on items stores the expected answer for each quiz question. It is only exposed in API responses when is_quiz_item? is true, preventing accidental leakage on peer-review rubric items. The quiz_questionnaire_id integer column on teams lets each submitting team directly own its quiz questionnaire — a key change that makes per-team quizzes possible and replaces a previous approach that required manual wiring at the assignment level.
Two migrations were added to support the quiz features:
# db/migrate/20260423000001_add_correct_answer_to_items.rb
class AddCorrectAnswerToItems < ActiveRecord::Migration[8.0]
def change
add_column :items, :correct_answer, :string
end
end
# db/migrate/20260424000001_add_quiz_questionnaire_id_to_teams.rb
class AddQuizQuestionnaireIdToTeams < ActiveRecord::Migration[8.0]
def change
add_column :teams, :quiz_questionnaire_id, :integer, null: true, default: nil
add_index :teams, :quiz_questionnaire_id
end
end
The correct_answer column stores the expected answer for each quiz item. It is only exposed in API responses when is_quiz_item? is true, preventing accidental leakage on peer-review rubric items.
The quiz_questionnaire_id column on teams allows each submitting team to directly own its quiz questionnaire. This replaces a previous approach that required the instructor to manually wire a questionnaire to the assignment, and is the key change that makes per-team quizzes possible.
2) Quiz-Aware Scoring in Response Model
Quiz responses are identified by the invariant reviewer_id == reviewee_id on the associated ResponseMap — no STI type column is needed. For text and choice quiz items the student's answer is stored in the comments column (not the numeric answer column), so scoring uses case-insensitive string equality. Both spaced names ("Text field", "Multiple choice") and CamelCase names ("TextField", "MultipleChoiceRadio") are handled because the frontend historically used both conventions. The final score is returned in the PATCH /responses/:id/submit response body as total_score and displayed to the student before the redirect.
The core scoring logic in Response#aggregate_questionnaire_score was extended to handle quiz responses:
def aggregate_questionnaire_score
sum = 0
is_quiz = map.reviewer_id == map.reviewee_id
comment_scored_types = %w[
TextField MultipleChoiceRadio MultipleChoiceCheckbox
Text\ field Multiple\ choice Multiple\ choice\ checkbox
].freeze
scores.each do |s|
if is_quiz && comment_scored_types.include?(s.item.question_type)
correct = s.item.correct_answer.to_s.strip.downcase
student_answer = s.comments.to_s.strip.downcase
sum += (student_answer == correct && correct.present? ? 1 : 0) * (s.item.weight || 1)
else
sum += s.answer * (s.item.weight || 1) unless s.answer.nil?
end
end
sum
end
Both spaced names ("Text field", "Multiple choice") and CamelCase names ("TextField", "MultipleChoiceRadio") are handled because the frontend historically used both conventions.
3) StudentTask Quiz Gateway Fields
Four fields were added to StudentTask so the frontend can make gatekeeping decisions without additional API calls: require_quiz, has_quiz_questionnaire, quiz_questionnaire_id, and quiz_taken (true only when a submitted Response exists against the student's QuizResponseMap). The frontend AssignedReviews component uses these fields to gate each review row — if require_quiz && has_quiz_questionnaire && !quiz_taken, a yellow "Take Quiz" button is shown instead of the review button.
Four fields were added to StudentTask:
attr_accessor :assignment, :assignment_id, :current_stage, :participant,
:stage_deadline, :topic, :permission_granted,
:require_quiz, :quiz_taken, :has_quiz_questionnaire, :quiz_questionnaire_id
The from_participant factory method was updated to compute these fields:
def self.from_participant(participant)
asgn = participant.assignment
return nil unless asgn
review_maps = ReviewResponseMap.where(reviewer_id: participant.id)
quiz_q_id = review_maps.filter_map { |m| Team.find_by(id: m.reviewee_id)&.quiz_questionnaire_id }.first
quiz_taken = QuizResponseMap.where(reviewer_id: participant.id, reviewed_object_id: quiz_q_id)
.joins(:responses)
.where(responses: { is_submitted: true })
.exists? if quiz_q_id
new(
assignment: asgn.name,
assignment_id: asgn.id,
require_quiz: asgn.require_quiz || false,
has_quiz_questionnaire: quiz_q_id.present?,
quiz_questionnaire_id: quiz_q_id,
quiz_taken: quiz_taken || false,
# ... other fields
)
end
4) QuizResponseMapsController
A QuizResponseMap is self-referential: reviewer_id == reviewee_id, both pointing to the reviewer's own AssignmentParticipant record. This invariant is what distinguishes quiz maps from peer-review maps throughout the system. The endpoint is idempotent — if a map already exists for this student/questionnaire pair it is returned as-is rather than creating a duplicate, making it safe for the frontend to call on every "Take Quiz" click.
A new controller handles quiz map creation:
# POST /quiz_response_maps
def create
# ... validate params, find assignment, resolve quiz questionnaire from team ...
map = QuizResponseMap.find_by(
reviewed_object_id: quiz_questionnaire.id,
reviewer_id: reviewer_participant.id,
reviewee_id: reviewer_participant.id
) || QuizResponseMap.new(...)
render json: {
quiz_map_id: map.id,
quiz_questionnaire_id: quiz_questionnaire.id,
reviewer_participant_id: reviewer_participant.id
}, status: :created
end
5) ResponseMapsController — Quiz Map Filtering
The index action must return only peer-review maps; quiz maps must not appear in the reviewer table. The primary guard next if map.reviewer_id == map.reviewee_id is reliable regardless of accidental id coincidences between questionnaire ids and assignment ids. A secondary next unless assignment check acts as belt-and-suspenders. Each returned row is augmented with quiz_taken and quiz_questionnaire_id so the frontend can render the "Take Quiz" button without a second API call.
ResponseMapsController#index was updated to exclude quiz maps and include per-row quiz state for the frontend:
result = maps.filter_map do |map|
# E2619: skip quiz maps (reviewer_id == reviewee_id)
next if map.reviewer_id == map.reviewee_id
# belt-and-suspenders: reviewed_object_id must reference an assignment
assignment = Assignment.find_by(id: map.reviewed_object_id)
next unless assignment
team = Team.find_by(id: map.reviewee_id)
quiz_questionnaire_id = team&.quiz_questionnaire_id
quiz_taken = quiz_questionnaire_id.present? &&
QuizResponseMap.where(reviewer_id: map.reviewer_id, reviewed_object_id: quiz_questionnaire_id)
.joins("INNER JOIN responses ON responses.map_id = response_maps.id")
.where(responses: { is_submitted: true }).exists?
{ id: map.id, quiz_questionnaire_id:, quiz_taken:, ... }
end
6) Instructor "Create Quiz" Button (AssignReviewer)
When clicked, the button navigates to the questionnaire editor with URL parameters (type=Quiz, team_id, return_to) that cause the editor to link the created questionnaire back to the team automatically via PATCH /teams/:team_id/quiz_questionnaire. After saving, the editor redirects back to the reviewer page.
Note: This is a temporary solution. In the full Expertiza workflow, quiz creation is initiated by a submitting team member from their own task page — not by an instructor from the reviewer-assignment page. The button was placed here because the student-facing entry point was not yet implemented in this codebase and should be removed or relocated once the proper student team submission flow is in place.
An onCreateQuiz handler was added to the AssignReviewer page:
const onCreateQuiz = useCallback((teamId: number) => {
navigate(
`/questionnaires/new?type=Quiz` +
`&team_id=${teamId}` +
`&return_to=${encodeURIComponent(location.pathname + location.search)}`
);
}, [navigate, location]);
After the questionnaire is saved, QuestionnaireEditor reads team_id and return_to from the URL, calls PATCH /teams/:team_id/quiz_questionnaire, and redirects back to the reviewer page.
7) Student "Take Quiz" Button (AssignedReviews)
The per-row quiz state (quiz_taken, has_quiz_questionnaire, quiz_questionnaire_id) is returned directly in the GET /response_maps response so no extra API call is needed to decide which button to show. When the student clicks "Take Quiz", the frontend first calls POST /quiz_response_maps (idempotent) to obtain or reuse a quiz map id, then navigates to the existing TeammateReview page with a redirect_after parameter encoding the peer-review URL. After the quiz is submitted the page auto-redirects to the actual review.
The AssignedReviews component now reads per-row quiz state from the response maps API response. When require_quiz && hasQuizQuestionnaire && !quizCompleted, a yellow "Take Quiz" button is shown:
const handleTakeQuiz = async (review: AssignedReviewRow, reviewUrl: string) => {
const res = await axiosClient.post('/quiz_response_maps', {
assignment_id: review.assignmentId,
reviewer_user_id: currentUser.id,
reviewee_team_id: review.revieweeTeamId,
});
const { quiz_map_id, quiz_questionnaire_id } = res.data;
navigate(
`/student_teams/teammate_review?` +
`map_id=${quiz_map_id}` +
`&questionnaire_id=${quiz_questionnaire_id}` +
`&questionnaire_type=Quiz` +
`&redirect_after=${encodeURIComponent(reviewUrl)}`
);
};
8) Quiz Mode in TeammateReview
Reusing the existing TeammateReview page for quiz-taking avoids duplicating the form rendering logic. Quiz mode is activated by questionnaire_type=Quiz in the URL, which causes the page to fetch quiz questionnaire items, disable the "Save Draft" button (quizzes are single-submission), display the score after submission, and show a "Proceed to Review" button that navigates to the redirect_after URL.
The existing TeammateReview page was extended with a quiz mode:
if (isQuizMode) {
setQuizScore(submitRes.data?.total_score ?? null);
}
9) Correct Answer Fields in Questionnaire Editor
When the questionnaire type is "Quiz", each item in QuestionnaireItemsFieldArray needs a "Correct answer" input whose control type depends on the question type. A dropdown makes sense for choice questions (the options are already defined), a bounded number input for Scale, a checkbox for Checkbox, and a free-text input for TextField (scored case-insensitively). The correct_answer value is persisted through QuestionnairesController and serialised via Item#as_json only for quiz items.
QuestionnaireItemsFieldArray renders a "Correct answer" row for each quiz item. The input type varies by question type:
| Question type | Correct answer input |
|---|---|
| Text field | Free-text <input type="text">; scored case-insensitively at submission
|
| Multiple choice / Multiple choice checkbox | <select> pre-populated from the item's alternatives
|
| Scale | <input type="number"> bounded by the item's weight range
|
| Checkbox | <input type="checkbox"> (correct = checked)
|
10) GET /questions/quiz_types Endpoint
Hard-coding the list of allowed quiz item types in the frontend would create a maintenance hazard every time a new type is added to the backend. The GET /questions/quiz_types endpoint lets the frontend fetch the authoritative list at runtime. The same constant is used in the create action to validate incoming item types, returning 422 if an unsupported type is submitted for a quiz questionnaire.
A new endpoint returns the allowed item types for quiz questionnaires so the frontend does not hard-code the list:
QUIZ_ITEM_TYPES = %w[TextField MultipleChoiceRadio MultipleChoiceCheckbox Scale Checkbox].freeze
# GET /questions/quiz_types
def quiz_types
render json: QUIZ_ITEM_TYPES, status: :ok
end
The create action on QuestionsController also validates that quiz questionnaires only accept items of these types, returning 422 with an error message otherwise.
Test Plan
Tests were added for all new and modified backend components. The full suite passes with 0 failures.
Pre-Test Setup
All request specs use the shared create_roles_hierarchy helper and JWT-based auth:
before(:all) { @roles = create_roles_hierarchy }
let(:token) { JsonWebToken.encode({ id: instructor.id }) }
let(:Authorization) { "Bearer #{token}" }
Model: Response — Quiz Scoring
11 new examples in spec/models/response_spec.rb validate the quiz scoring path, covering both spaced and CamelCase question type names, correct/incorrect answers, blank answers, multi-item accumulation, and maximum score calculation.
describe '#aggregate_questionnaire_score (quiz)' do
it 'scores a correct "Text field" answer' do
item = make_quiz_item(question_type: 'Text field', correct_answer: 'Paris', weight: 2)
answer = make_quiz_answer(item: item, comments: 'paris') # case-insensitive
r = quiz_response([answer])
expect(r.aggregate_questionnaire_score).to eq(2)
end
it 'scores an incorrect "Text field" answer as 0' do
item = make_quiz_item(question_type: 'Text field', correct_answer: 'Paris', weight: 2)
answer = make_quiz_answer(item: item, comments: 'London')
r = quiz_response([answer])
expect(r.aggregate_questionnaire_score).to eq(0)
end
it 'gives 0 when the comments column is blank' do
item = make_quiz_item(question_type: 'Text field', correct_answer: 'Paris', weight: 2)
answer = make_quiz_answer(item: item, comments: '')
r = quiz_response([answer])
expect(r.aggregate_questionnaire_score).to eq(0)
end
end
Model: StudentTask — Quiz Gateway Fields
7 examples in spec/models/student_task_spec.rb verify the quiz gateway fields are populated by from_participant and serialised by as_json.
Request: QuizResponseMaps
6 examples in spec/requests/api/v1/quiz_response_maps_controller_spec.rb:
| Test | Expected status |
|---|---|
| Happy path — creates map and returns IDs | 201 |
| Idempotent — reuses existing map on repeat call | 201 |
Missing assignment_id |
400 |
Missing reviewer_user_id |
400 |
| Assignment not found (id = 999999999) | 404 |
| Team has no quiz questionnaire | 422 |
Request: ResponseMaps
7 examples in spec/requests/api/v1/response_maps_controller_spec.rb:
| Test | Expected status |
|---|---|
| GET — returns peer-review maps, excludes quiz maps | 200 |
GET — each entry includes quiz_taken and quiz_questionnaire_id |
200 |
| GET — returns empty array when reviewer has no maps | 200 |
GET — missing reviewer_user_id |
400 |
| POST — creates ReviewResponseMap and returns IDs | 201 |
| POST — idempotent, returns same map on repeat call | 201 |
| POST — missing required param | 400 |
Request: Questions — Quiz Types
3 new examples in spec/requests/api/v1/questions_spec.rb:
describe 'GET /questions/quiz_types' do
it 'returns 200 with the allowed quiz item type strings' do
get '/questions/quiz_types', headers: { 'Authorization' => auth_header }
types = JSON.parse(response.body)
expect(types).to include('TextField', 'MultipleChoiceRadio', 'MultipleChoiceCheckbox')
end
end
Test Coverage Summary
| Spec file | Examples before | Examples after |
|---|---|---|
spec/models/student_task_spec.rb |
3 (failing) | 7 ✅ |
spec/models/response_spec.rb |
11 | 22 ✅ |
spec/requests/api/v1/questions_spec.rb |
19 | 22 ✅ |
spec/requests/api/v1/quiz_response_maps_controller_spec.rb |
0 | 6 ✅ |
spec/requests/api/v1/response_maps_controller_spec.rb |
0 | 7 ✅ |
| Total new examples | 27 |
Files Modified
Backend (Ruby on Rails)
| File | Change |
|---|---|
app/models/response.rb |
Added quiz-aware scoring to aggregate_questionnaire_score and maximum_score
|
app/models/student_task.rb |
Added four quiz gateway fields; updated from_participant and as_json
|
app/models/Item.rb |
Added QUIZ_ITEM_TYPES, is_quiz_item?, correct_answer_only_for_quiz validation, and conditional as_json
|
app/models/team.rb |
Added quiz_questionnaire_id attribute and quiz_questionnaire association
|
app/models/quiz_response_map.rb |
Minor documentation updates |
app/controllers/questions_controller.rb |
Added GET /questions/quiz_types; added quiz item type validation in create
|
app/controllers/quiz_response_maps_controller.rb |
New controller: POST /quiz_response_maps
|
app/controllers/response_maps_controller.rb |
Updated index to filter quiz maps and return per-row quiz state; added create and destroy
|
app/controllers/teams_controller.rb |
Added PATCH /teams/:id/quiz_questionnaire
|
app/controllers/questionnaires_controller.rb |
Exposed correct_answer in strong parameters
|
config/routes.rb |
Added routes for quiz_response_maps, quiz_types, and quiz_questionnaire on teams |
db/migrate/20260423000001_add_correct_answer_to_items.rb |
New migration: adds correct_answer string column to items
|
db/migrate/20260424000001_add_quiz_questionnaire_id_to_teams.rb |
New migration: adds quiz_questionnaire_id integer column + index to teams
|
spec/models/student_task_spec.rb |
Fixed existing test failures; added quiz gateway field assertions |
spec/models/response_spec.rb |
Added 11 new quiz scoring tests |
spec/requests/api/v1/questions_spec.rb |
Added tests for quiz_types endpoint and quiz item creation/rejection
|
spec/requests/api/v1/quiz_response_maps_controller_spec.rb |
New spec: 6 tests covering happy path, idempotency, and error cases |
spec/requests/api/v1/response_maps_controller_spec.rb |
New spec: 7 tests covering quiz-map exclusion, quiz state fields, and POST CRUD |
Frontend (React/TypeScript)
| File | Change |
|---|---|
src/pages/StudentTasks/AssignedReviews.tsx |
Added "Take Quiz" button; per-row quiz state; handleTakeQuiz calling POST /quiz_response_maps
|
src/pages/Assignments/AssignReviewer.tsx |
Added "Create Quiz" button that navigates to the questionnaire editor pre-linked to the team |
src/pages/Questionnaires/QuestionnaireItemsFieldArray.tsx |
Added correct-answer row for each quiz item type |
src/pages/Questionnaires/QuestionnaireEditor.tsx |
Added team-quiz creation flow: links new questionnaire to team via PATCH /teams/:id/quiz_questionnaire
|
src/pages/Student Teams/TeammateReview.tsx |
Added quiz mode (isQuizMode), quiz score display, and redirect_after param support
|
src/pages/Assignments/AssignmentEditor.tsx |
Ensured require_quiz checkbox is wired to the form state
|
src/pages/Assignments/AssignmentUtil.ts |
Added require_quiz to IAssignmentFormValues
|
src/pages/Questionnaires/QuestionnaireUtils.tsx |
Added correct_answer to IItem; updated transformQuestionnaireRequest
|
src/components/Form/FormSelect.tsx |
Documentation only (JSDoc) |
Github Pull Request
- Frontend: https://github.com/expertiza/reimplementation-front-end/pull/179
- Backend: https://github.com/expertiza/reimplementation-back-end/pull/345
Video
Mentor
Ed Gehringer (efg@ncsu.edu)
Team Member
- An Mai (atmai@ncsu.edu)
- Mekhi Parker (mrparke4@ncsu.edu)
- Tejas Manoj Desai (tdesai@ncsu.edu)


