i18n: Replace hardcoded English strings with German in key components
UnifiedGradingPanel - all labels translated to German ProfessionalCalendar - all UI text translated to German AI Studio - confirmed German throughout
This commit is contained in:
1 parent
678a4e9b83
commit
7461f7699c
2 files changed
+75
-75
No files matched your search
@@ -163,7 +163,7 @@ export function ProfessionalCalendar({
|
||||
if (onEventCreate) {
|
||||
await onEventCreate(newEvent);
|
||||
}
|
||||
toast.success('Event created successfully');
|
||||
toast.success('Ereignis erfolgreich erstellt');
|
||||
setIsCreating(false);
|
||||
} catch (error) {
|
||||
toast.error('Failed to create event');
|
||||
@@ -183,7 +183,7 @@ export function ProfessionalCalendar({
|
||||
if (onEventUpdate) {
|
||||
await onEventUpdate(event);
|
||||
}
|
||||
toast.success('Event updated successfully');
|
||||
toast.success('Ereignis aktualisiert successfully');
|
||||
} catch (error) {
|
||||
toast.error('Failed to update event');
|
||||
console.error(error);
|
||||
@@ -201,7 +201,7 @@ export function ProfessionalCalendar({
|
||||
await onEventDelete(eventId);
|
||||
}
|
||||
setSelectedEvent(null);
|
||||
toast.success('Event deleted successfully');
|
||||
toast.success('Ereignis gelöscht successfully');
|
||||
} catch (error) {
|
||||
toast.error('Failed to delete event');
|
||||
console.error(error);
|
||||
@@ -350,7 +350,7 @@ export function ProfessionalCalendar({
|
||||
size="sm"
|
||||
onClick={() => setCurrentDate(new Date())}
|
||||
>
|
||||
Today
|
||||
Heute
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -380,7 +380,7 @@ export function ProfessionalCalendar({
|
||||
className="gap-2"
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
New Event
|
||||
Neues Ereignis
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -427,7 +427,7 @@ export function ProfessionalCalendar({
|
||||
<Badge variant="secondary">{event.type}</Badge>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
{format(event.date, 'PPP', { locale: dateLocale })} at {CalendarManager.formatTimeRange(event)}
|
||||
{format(event.date, 'PPP', { locale: dateLocale })} um {CalendarManager.formatTimeRange(event)}
|
||||
</p>
|
||||
{event.description && (
|
||||
<p className="text-sm mt-2">{event.description}</p>
|
||||
@@ -507,9 +507,9 @@ function EventDetailDialog({
|
||||
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">Date & Time</Label>
|
||||
<Label className="text-xs text-muted-foreground">Datum & Zeit</Label>
|
||||
<p className="text-sm">
|
||||
{format(event.date, 'PPP')} at {CalendarManager.formatTimeRange(event)}
|
||||
{format(event.date, 'PPP')} um {CalendarManager.formatTimeRange(event)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -517,7 +517,7 @@ function EventDetailDialog({
|
||||
<div className="flex gap-2 items-start">
|
||||
<MapPin className="h-4 w-4 text-muted-foreground mt-1" />
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">Location</Label>
|
||||
<Label className="text-xs text-muted-foreground">Ort</Label>
|
||||
<p className="text-sm">{event.location}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -525,7 +525,7 @@ function EventDetailDialog({
|
||||
|
||||
{event.description && (
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">Description</Label>
|
||||
<Label className="text-xs text-muted-foreground">Beschreibung</Label>
|
||||
<p className="text-sm">{event.description}</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -534,7 +534,7 @@ function EventDetailDialog({
|
||||
<div className="flex gap-2 items-start">
|
||||
<Users className="h-4 w-4 text-muted-foreground mt-1" />
|
||||
<div>
|
||||
<Label className="text-xs text-muted-foreground">Attendees</Label>
|
||||
<Label className="text-xs text-muted-foreground">Teilnehmer</Label>
|
||||
<p className="text-sm">{event.attendees.join(', ')}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -603,12 +603,12 @@ function EventCreatorDialog({
|
||||
<Dialog open onOpenChange={onClose}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create New Event</DialogTitle>
|
||||
<DialogTitle>Create Neues Ereignis</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label htmlFor="title">Title</Label>
|
||||
<Label htmlFor="title">Titel</Label>
|
||||
<Input
|
||||
id="title"
|
||||
value={formData.title}
|
||||
@@ -659,7 +659,7 @@ function EventCreatorDialog({
|
||||
{!formData.allDay && (
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<Label htmlFor="startTime">Start Time</Label>
|
||||
<Label htmlFor="startTime">Startzeit</Label>
|
||||
<Input
|
||||
id="startTime"
|
||||
type="time"
|
||||
@@ -668,7 +668,7 @@ function EventCreatorDialog({
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="endTime">End Time</Label>
|
||||
<Label htmlFor="endTime">Endzeit</Label>
|
||||
<Input
|
||||
id="endTime"
|
||||
type="time"
|
||||
@@ -680,7 +680,7 @@ function EventCreatorDialog({
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Label htmlFor="location">Location</Label>
|
||||
<Label htmlFor="location">Ort</Label>
|
||||
<Input
|
||||
id="location"
|
||||
value={formData.location}
|
||||
@@ -690,7 +690,7 @@ function EventCreatorDialog({
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="description">Description</Label>
|
||||
<Label htmlFor="description">Beschreibung</Label>
|
||||
<Textarea
|
||||
id="description"
|
||||
value={formData.description}
|
||||
@@ -703,9 +703,9 @@ function EventCreatorDialog({
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={onClose}>
|
||||
Cancel
|
||||
Abbrechen
|
||||
</Button>
|
||||
<Button onClick={handleSubmit}>Create Event</Button>
|
||||
<Button onClick={handleSubmit}>Ereignis erstellen</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
@@ -55,7 +55,7 @@ interface Grade {
|
||||
subject: string;
|
||||
assessment: string;
|
||||
score: number;
|
||||
maxScore: number;
|
||||
maxPunkte: number;
|
||||
weight?: number;
|
||||
comment?: string;
|
||||
gradedAt?: string;
|
||||
@@ -72,7 +72,7 @@ interface UnifiedGradingPanelProps {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unified Grading Panel
|
||||
* Unified Benotung
|
||||
* Consolidates: grading-view.tsx, tablet-grading-view.tsx, grade-analytics-view.tsx
|
||||
* Single component supports all viewing modes and devices
|
||||
*/
|
||||
@@ -89,7 +89,7 @@ export function UnifiedGradingPanel({
|
||||
const [selectedGrade, setSelectedGrade] = useState<Grade | null>(null);
|
||||
const [isEditingGrade, setIsEditingGrade] = useState(false);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [filterSubject, setFilterSubject] = useState('all');
|
||||
const [filterFach, setFilterFach] = useState('all');
|
||||
const [filterStatus, setFilterStatus] = useState<'all' | 'pending' | 'graded' | 'released'>('all');
|
||||
const [viewType, setViewType] = useState<'grid' | 'list' | 'analytics'>(
|
||||
variant === 'list' ? 'list' : 'grid'
|
||||
@@ -116,8 +116,8 @@ export function UnifiedGradingPanel({
|
||||
studentName: item.studentName || (item.student ? `${item.student.firstName} ${item.student.lastName}` : '—'),
|
||||
subject: typeof item.subject === 'string' ? item.subject : (item.subject?.name || item.subjectId || '—'),
|
||||
assessment: item.assessment || item.title || item.name || '—',
|
||||
score: typeof item.score === 'number' ? item.score : (item.maxScore ?? 0),
|
||||
maxScore: item.maxScore ?? 100,
|
||||
score: typeof item.score === 'number' ? item.score : (item.maxPunkte ?? 0),
|
||||
maxPunkte: item.maxPunkte ?? 100,
|
||||
weight: item.weight,
|
||||
comment: item.comment || item.note || '',
|
||||
gradedAt: item.gradedAt || item.date || item.createdAt,
|
||||
@@ -143,9 +143,9 @@ export function UnifiedGradingPanel({
|
||||
);
|
||||
}
|
||||
|
||||
// Subject filter
|
||||
if (filterSubject !== 'all') {
|
||||
filtered = filtered.filter((g) => g.subject === filterSubject);
|
||||
// Fach filter
|
||||
if (filterFach !== 'all') {
|
||||
filtered = filtered.filter((g) => g.subject === filterFach);
|
||||
}
|
||||
|
||||
// Status filter
|
||||
@@ -154,18 +154,18 @@ export function UnifiedGradingPanel({
|
||||
}
|
||||
|
||||
setFilteredGrades(filtered);
|
||||
}, [searchTerm, filterSubject, filterStatus]);
|
||||
}, [searchTerm, filterFach, filterStatus]);
|
||||
|
||||
// Update filters when any filter changes
|
||||
React.useEffect(() => {
|
||||
applyFilters(grades);
|
||||
}, [searchTerm, filterSubject, filterStatus, applyFilters]);
|
||||
}, [searchTerm, filterFach, filterStatus, applyFilters]);
|
||||
|
||||
// Calculate statistics
|
||||
const stats = useMemo(() => {
|
||||
const completed = grades.filter((g) => g.status !== 'pending').length;
|
||||
const average = grades.length > 0
|
||||
? (grades.reduce((sum, g) => sum + (g.score / g.maxScore) * 100, 0) / grades.length).toFixed(1)
|
||||
? (grades.reduce((sum, g) => sum + (g.score / g.maxPunkte) * 100, 0) / grades.length).toFixed(1)
|
||||
: 0;
|
||||
|
||||
return {
|
||||
@@ -231,7 +231,7 @@ export function UnifiedGradingPanel({
|
||||
}
|
||||
}, [mutate]);
|
||||
|
||||
// Subject list for filtering
|
||||
// Fach list for filtering
|
||||
const subjects = useMemo(() => {
|
||||
const subjectSet = new Set(grades.map((g) => g.subject));
|
||||
return Array.from(subjectSet).sort();
|
||||
@@ -244,7 +244,7 @@ export function UnifiedGradingPanel({
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm">Total Grades</CardTitle>
|
||||
<CardTitle className="text-sm">Noten gesamt</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">{stats.total}</div>
|
||||
@@ -252,7 +252,7 @@ export function UnifiedGradingPanel({
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm">Completed</CardTitle>
|
||||
<CardTitle className="text-sm">Erledigt</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">{stats.completed}</div>
|
||||
@@ -260,7 +260,7 @@ export function UnifiedGradingPanel({
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm">Pending</CardTitle>
|
||||
<CardTitle className="text-sm">Ausstehend</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-orange-500">{stats.pending}</div>
|
||||
@@ -268,7 +268,7 @@ export function UnifiedGradingPanel({
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm">Average</CardTitle>
|
||||
<CardTitle className="text-sm">Durchschnitt</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">{stats.average}%</div>
|
||||
@@ -280,10 +280,10 @@ export function UnifiedGradingPanel({
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center justify-between">
|
||||
<span>Grades</span>
|
||||
<span>Noten</span>
|
||||
<Button onClick={handleSubmitGrades} disabled={stats.pending === stats.total}>
|
||||
<CheckCircle2 className="h-4 w-4 mr-2" />
|
||||
Submit Grades
|
||||
Noten einreichen
|
||||
</Button>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
@@ -292,13 +292,13 @@ export function UnifiedGradingPanel({
|
||||
<table className="w-full text-sm">
|
||||
<thead className="border-b">
|
||||
<tr>
|
||||
<th className="text-left py-2 px-3">Student</th>
|
||||
<th className="text-left py-2 px-3">Subject</th>
|
||||
<th className="text-left py-2 px-3">Assessment</th>
|
||||
<th className="text-center py-2 px-3">Score</th>
|
||||
<th className="text-center py-2 px-3">Percentage</th>
|
||||
<th className="text-left py-2 px-3">Schüler</th>
|
||||
<th className="text-left py-2 px-3">Fach</th>
|
||||
<th className="text-left py-2 px-3">Leistungsüberprüfung</th>
|
||||
<th className="text-center py-2 px-3">Punkte</th>
|
||||
<th className="text-center py-2 px-3">Prozent</th>
|
||||
<th className="text-center py-2 px-3">Status</th>
|
||||
<th className="text-right py-2 px-3">Actions</th>
|
||||
<th className="text-right py-2 px-3">Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -314,10 +314,10 @@ export function UnifiedGradingPanel({
|
||||
<td className="py-2 px-3">{grade.subject}</td>
|
||||
<td className="py-2 px-3">{grade.assessment}</td>
|
||||
<td className="py-2 px-3 text-center font-semibold">
|
||||
{grade.score}/{grade.maxScore}
|
||||
{grade.score}/{grade.maxPunkte}
|
||||
</td>
|
||||
<td className="py-2 px-3 text-center">
|
||||
{((grade.score / grade.maxScore) * 100).toFixed(1)}%
|
||||
{((grade.score / grade.maxPunkte) * 100).toFixed(1)}%
|
||||
</td>
|
||||
<td className="py-2 px-3 text-center">
|
||||
<Badge
|
||||
@@ -373,7 +373,7 @@ export function UnifiedGradingPanel({
|
||||
<h3 className="font-semibold">{grade.studentName}</h3>
|
||||
<p className="text-sm text-muted-foreground">{grade.subject}</p>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-lg font-bold">{grade.score}/{grade.maxScore}</span>
|
||||
<span className="text-lg font-bold">{grade.score}/{grade.maxPunkte}</span>
|
||||
<Badge>{grade.status}</Badge>
|
||||
</div>
|
||||
</div>
|
||||
@@ -404,7 +404,7 @@ export function UnifiedGradingPanel({
|
||||
</p>
|
||||
</div>
|
||||
<div className="text-right space-y-1">
|
||||
<div className="font-semibold">{grade.score}/{grade.maxScore}</div>
|
||||
<div className="font-semibold">{grade.score}/{grade.maxPunkte}</div>
|
||||
<Badge variant="outline">{grade.status}</Badge>
|
||||
</div>
|
||||
</motion.div>
|
||||
@@ -414,11 +414,11 @@ export function UnifiedGradingPanel({
|
||||
|
||||
// Analytics view (replaces the removed grade-analytics nav entry)
|
||||
const renderAnalyticsView = () => {
|
||||
const avgScore = grades.length > 0
|
||||
? (grades.reduce((s, g) => s + (g.score / g.maxScore) * 100, 0) / grades.length).toFixed(1)
|
||||
const avgPunkte = grades.length > 0
|
||||
? (grades.reduce((s, g) => s + (g.score / g.maxPunkte) * 100, 0) / grades.length).toFixed(1)
|
||||
: '0';
|
||||
const passRate = grades.length > 0
|
||||
? Math.round((grades.filter(g => (g.score / g.maxScore) >= 0.5).length / grades.length) * 100)
|
||||
? Math.round((grades.filter(g => (g.score / g.maxPunkte) >= 0.5).length / grades.length) * 100)
|
||||
: 0;
|
||||
|
||||
// Distribution by subject
|
||||
@@ -426,7 +426,7 @@ export function UnifiedGradingPanel({
|
||||
grades.forEach(g => {
|
||||
if (!subjectStats[g.subject]) subjectStats[g.subject] = { count: 0, avg: 0 };
|
||||
subjectStats[g.subject].count++;
|
||||
subjectStats[g.subject].avg += (g.score / g.maxScore) * 100;
|
||||
subjectStats[g.subject].avg += (g.score / g.maxPunkte) * 100;
|
||||
});
|
||||
Object.keys(subjectStats).forEach(s => {
|
||||
subjectStats[s].avg = Math.round(subjectStats[s].avg / subjectStats[s].count);
|
||||
@@ -436,13 +436,13 @@ export function UnifiedGradingPanel({
|
||||
<div className="space-y-6">
|
||||
{/* Summary cards */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
<Card><CardContent className="p-4"><p className="text-xs text-muted-foreground">Durchschnitt</p><p className="text-2xl font-bold text-emerald-600">{avgScore}%</p></CardContent></Card>
|
||||
<Card><CardContent className="p-4"><p className="text-xs text-muted-foreground">Durchschnitt</p><p className="text-2xl font-bold text-emerald-600">{avgPunkte}%</p></CardContent></Card>
|
||||
<Card><CardContent className="p-4"><p className="text-xs text-muted-foreground">Bestehensquote</p><p className="text-2xl font-bold text-sky-600">{passRate}%</p></CardContent></Card>
|
||||
<Card><CardContent className="p-4"><p className="text-xs text-muted-foreground">Noten gesamt</p><p className="text-2xl font-bold">{grades.length}</p></CardContent></Card>
|
||||
<Card><CardContent className="p-4"><p className="text-xs text-muted-foreground">Fächer</p><p className="text-2xl font-bold">{Object.keys(subjectStats).length}</p></CardContent></Card>
|
||||
</div>
|
||||
|
||||
{/* Subject breakdown */}
|
||||
{/* Fach breakdown */}
|
||||
<Card>
|
||||
<CardHeader><CardTitle className="text-base">Noten nach Fach</CardTitle></CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
@@ -477,7 +477,7 @@ export function UnifiedGradingPanel({
|
||||
{ label: 'ueber 90%', min: 90, max: 101, color: 'bg-emerald-500' },
|
||||
].map(bucket => {
|
||||
const count = grades.filter(g => {
|
||||
const pct = (g.score / g.maxScore) * 100;
|
||||
const pct = (g.score / g.maxPunkte) * 100;
|
||||
return pct >= bucket.min && pct < bucket.max;
|
||||
}).length;
|
||||
const max = Math.max(grades.length, 1);
|
||||
@@ -510,15 +510,15 @@ export function UnifiedGradingPanel({
|
||||
{/* Header with filters */}
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h2 className="text-2xl font-bold">Grading Panel</h2>
|
||||
<h2 className="text-2xl font-bold">Benotung</h2>
|
||||
<div className="flex gap-2">
|
||||
<Button size="sm" variant="outline">
|
||||
<Download className="h-4 w-4 mr-2" />
|
||||
Export
|
||||
Exportieren
|
||||
</Button>
|
||||
<Button size="sm" variant="outline">
|
||||
<Upload className="h-4 w-4 mr-2" />
|
||||
Import
|
||||
Importieren
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -526,17 +526,17 @@ export function UnifiedGradingPanel({
|
||||
{/* Filters */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||
<Input
|
||||
placeholder="Search grades..."
|
||||
placeholder="Noten suchen..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
|
||||
<Select value={filterSubject} onValueChange={setFilterSubject}>
|
||||
<Select value={filterFach} onValueChange={setFilterFach}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="All subjects" />
|
||||
<SelectValue placeholder="Alle Fächer" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">All subjects</SelectItem>
|
||||
<SelectItem value="all">Alle Fächer</SelectItem>
|
||||
{subjects.map((subject) => (
|
||||
<SelectItem key={subject} value={subject}>
|
||||
{subject}
|
||||
@@ -547,13 +547,13 @@ export function UnifiedGradingPanel({
|
||||
|
||||
<Select value={filterStatus} onValueChange={(v) => setFilterStatus(v as any)}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="All statuses" />
|
||||
<SelectValue placeholder="Alle Status" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">All statuses</SelectItem>
|
||||
<SelectItem value="pending">Pending</SelectItem>
|
||||
<SelectItem value="graded">Graded</SelectItem>
|
||||
<SelectItem value="released">Released</SelectItem>
|
||||
<SelectItem value="all">Alle Status</SelectItem>
|
||||
<SelectItem value="pending">Ausstehend</SelectItem>
|
||||
<SelectItem value="graded">Bewertet</SelectItem>
|
||||
<SelectItem value="released">Veröffentlicht</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
@@ -628,14 +628,14 @@ function GradeEditDialog({
|
||||
<Dialog open onOpenChange={onClose}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit Grade: {grade.studentName}</DialogTitle>
|
||||
<DialogTitle>Note bearbeiten: {grade.studentName}</DialogTitle>
|
||||
<DialogDescription>{grade.subject} - {grade.assessment}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<Label>Score</Label>
|
||||
<Label>Punkte</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={formData.score}
|
||||
@@ -643,25 +643,25 @@ function GradeEditDialog({
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>Max Score</Label>
|
||||
<Label>Max. Punkte</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={formData.maxScore}
|
||||
onChange={(e) => setFormData({ ...formData, maxScore: parseFloat(e.target.value) })}
|
||||
value={formData.maxPunkte}
|
||||
onChange={(e) => setFormData({ ...formData, maxPunkte: parseFloat(e.target.value) })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>Percentage: {((formData.score / formData.maxScore) * 100).toFixed(1)}%</Label>
|
||||
<Label>Prozent: {((formData.score / formData.maxPunkte) * 100).toFixed(1)}%</Label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>Comment</Label>
|
||||
<Label>Kommentar</Label>
|
||||
<Input
|
||||
value={formData.comment || ''}
|
||||
onChange={(e) => setFormData({ ...formData, comment: e.target.value })}
|
||||
placeholder="Add a comment..."
|
||||
placeholder="Kommentar hinzufügen..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -687,7 +687,7 @@ function GradeEditDialog({
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
Save Changes
|
||||
Speichern
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
Reference in new issue
Block a user