Add optional audio response for students in homework submissions

- Course: add allowAudio toggle (per-course setting, off by default)
- HomeworkSubmission: add audioUrl field
- Student: AudioRecorder in homework form when allowAudio is enabled
- Student: show audio player in submission view and curator feedback view
- Curator: show student audio on submission detail page
- AudioRecorder: accept uploadUrl prop (reused for student/curator)
- API: /api/student/audio-upload route for S3 upload

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-08 14:17:46 +05:00
parent 3855bbd4be
commit 48a9398905
10 changed files with 152 additions and 33 deletions
+3 -2
View File
@@ -5,9 +5,10 @@ import { useState, useRef } from "react";
interface AudioRecorderProps {
value: string | null;
onChange: (url: string | null) => void;
uploadUrl?: string;
}
export function AudioRecorder({ value, onChange }: AudioRecorderProps) {
export function AudioRecorder({ value, onChange, uploadUrl = "/api/curator/audio-upload" }: AudioRecorderProps) {
const [state, setState] = useState<"idle" | "recording" | "recorded" | "uploading">("idle");
const [localUrl, setLocalUrl] = useState<string | null>(null);
const mediaRecorder = useRef<MediaRecorder | null>(null);
@@ -46,7 +47,7 @@ export function AudioRecorder({ value, onChange }: AudioRecorderProps) {
const blob = new Blob(chunks.current, { type: mimeType.current });
const form = new FormData();
form.append("file", blob, "audio-response.webm");
const res = await fetch("/api/curator/audio-upload", { method: "POST", body: form });
const res = await fetch(uploadUrl, { method: "POST", body: form });
const data = await res.json();
if (data.url) {
onChange(data.url);