Files
lms-sb/src/components/admin/homework-editor.tsx
T
admins 543d5b2d5e Add homework system (admin, student, curator)
Admin:
- HomeworkEditor in lesson page: create/update/delete assignment description

Student:
- HomeworkSection in lesson page: view assignment, submit text + files
- Resubmission allowed until curator gives feedback
- Shows feedback from curator with date and name

Curator:
- New layout with Second Brain dark sidebar (replaces green theme)
- /curator/dashboard: stats cards (pending, total, reviewed this week)
- /curator/homework: list of all submissions, pending highlighted
- /curator/homework/[id]: review submission, write feedback, redirect after send

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 14:13:24 +05:00

95 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState, useTransition } from "react";
import { saveHomework, deleteHomework } from "@/app/admin/courses/[courseId]/modules/[moduleId]/lessons/[lessonId]/homework-actions";
interface Props {
lessonId: string;
initial: { id: string; description: string } | null;
}
export function HomeworkEditor({ lessonId, initial }: Props) {
const [editing, setEditing] = useState(!initial);
const [text, setText] = useState(initial?.description ?? "");
const [saved, setSaved] = useState(false);
const [pending, startTransition] = useTransition();
const inputStyle = {
border: "2px solid var(--border)",
background: "var(--background)",
outline: "none",
width: "100%",
padding: "0.5rem 0.75rem",
fontSize: "0.875rem",
fontFamily: "inherit",
resize: "vertical" as const,
minHeight: "120px",
};
function handleSave() {
if (!text.trim()) return;
startTransition(async () => {
await saveHomework(lessonId, text.trim());
setSaved(true);
setEditing(false);
setTimeout(() => setSaved(false), 2000);
});
}
function handleDelete() {
if (!confirm("Удалить домашнее задание? Все сданные работы будут удалены.")) return;
startTransition(async () => {
await deleteHomework(lessonId);
setText("");
setEditing(true);
});
}
if (!editing && initial) {
return (
<div className="space-y-3">
<div className="px-4 py-3 text-sm whitespace-pre-wrap" style={{ border: "2px solid var(--border)", background: "var(--color-surface)" }}>
{text || initial.description}
</div>
<div className="flex gap-2">
<button onClick={() => setEditing(true)} className="btn-aubade text-xs px-3 py-1.5">
Редактировать
</button>
<button onClick={handleDelete} disabled={pending} className="text-xs px-3 py-1.5" style={{ color: "oklch(0.577 0.245 27.325)" }}>
Удалить ДЗ
</button>
{saved && <span className="text-xs self-center" style={{ color: "var(--muted-foreground)" }}> Сохранено</span>}
</div>
</div>
);
}
return (
<div className="space-y-3">
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
style={inputStyle}
placeholder="Опишите задание для студентов..."
onFocus={(e) => (e.currentTarget.style.borderColor = "var(--foreground)")}
onBlur={(e) => (e.currentTarget.style.borderColor = "var(--border)")}
/>
<div className="flex items-center gap-2">
<button
onClick={handleSave}
disabled={pending || !text.trim()}
className="btn-aubade btn-aubade-accent text-xs px-4 py-1.5"
style={{ opacity: pending || !text.trim() ? 0.6 : 1 }}
>
{pending ? "Сохранение..." : "Сохранить задание"}
</button>
{initial && (
<button onClick={() => { setEditing(false); setText(initial.description); }} className="text-xs" style={{ color: "var(--muted-foreground)" }}>
Отмена
</button>
)}
</div>
</div>
);
}