lang bugfix
All checks were successful
Build & Push Docker Image / docker (push) Successful in 1m50s

This commit is contained in:
Ahmed Darrazi 2025-12-18 23:35:27 +01:00
parent fd6ca8221f
commit 6ba9651f34
6 changed files with 63 additions and 63 deletions

View File

@ -4,48 +4,48 @@ import { format } from 'date-fns';
import { AlertCircle, Clock } from 'lucide-react'; import { AlertCircle, Clock } from 'lucide-react';
import AssignmentDialog from './assignment-dialog'; import AssignmentDialog from './assignment-dialog';
// Function to format date // Funktion zum Formatieren des Datums
const formatDate = (dateString: string | undefined) => { const formatDate = (dateString: string | undefined) => {
if (!dateString) return 'N/A'; if (!dateString) return 'k.A.';
const date = new Date(dateString); const date = new Date(dateString);
return format(date, 'MMMM dd, yyyy, hh:mm a'); return format(date, 'MMMM dd, yyyy, hh:mm a');
}; };
// Function to check if deadline has passed // Funktion zum Prüfen, ob die Frist abgelaufen ist
const isDeadlinePassed = (deadline: string) => { const isDeadlinePassed = (deadline: string) => {
if (!deadline) return false; if (!deadline) return false;
return new Date() > new Date(deadline); return new Date() > new Date(deadline);
}; };
// Function to get submission status // Funktion, um den Abgabestatus zu ermitteln
const getSubmissionStatus = (assignment: CourseAssignment) => { const getSubmissionStatus = (assignment: CourseAssignment) => {
if (!assignment.submissions || assignment.submissions.length === 0) { if (!assignment.submissions || assignment.submissions.length === 0) {
return { status: 'not_submitted', label: 'Not Submitted', variant: 'secondary' as const }; return { status: 'not_submitted', label: 'Nicht eingereicht', variant: 'secondary' as const };
} }
const latestSubmission = assignment.submissions[0]; const latestSubmission = assignment.submissions[0];
if (latestSubmission.status === 'graded') { if (latestSubmission.status === 'graded') {
return { status: 'graded', label: 'Graded', variant: 'default' as const }; return { status: 'graded', label: 'Bewertet', variant: 'default' as const };
} else if (latestSubmission.is_late) { } else if (latestSubmission.is_late) {
return { status: 'late', label: 'Late Submission', variant: 'destructive' as const }; return { status: 'late', label: 'Verspätete Abgabe', variant: 'destructive' as const };
} else { } else {
return { status: 'submitted', label: 'Submitted', variant: 'default' as const }; return { status: 'submitted', label: 'Eingereicht', variant: 'default' as const };
} }
}; };
export const AssignmentColumns: ColumnDef<CourseAssignment>[] = [ export const AssignmentColumns: ColumnDef<CourseAssignment>[] = [
{ {
accessorKey: 'title', accessorKey: 'title',
header: 'Title', header: 'Titel',
cell: ({ row }) => { cell: ({ row }) => {
const assignment = row.original; const assignment = row.original;
return ( return (
<div className="space-y-1 py-1"> <div className="space-y-1 py-1">
<p className="font-medium">{assignment.title}</p> <p className="font-medium">{assignment.title}</p>
<div className="text-muted-foreground flex items-center gap-4 text-sm"> <div className="text-muted-foreground flex items-center gap-4 text-sm">
<span>Total Marks: {assignment.total_mark}</span> <span>Gesamtpunktzahl: {assignment.total_mark}</span>
<span>Pass Marks: {assignment.pass_mark}</span> <span>Bestehenspunktzahl: {assignment.pass_mark}</span>
</div> </div>
</div> </div>
); );
@ -53,7 +53,7 @@ export const AssignmentColumns: ColumnDef<CourseAssignment>[] = [
}, },
{ {
accessorKey: 'deadline', accessorKey: 'deadline',
header: 'Deadline', header: 'Frist',
cell: ({ row }) => { cell: ({ row }) => {
const assignment = row.original; const assignment = row.original;
const deadlinePassed = isDeadlinePassed(assignment.deadline); const deadlinePassed = isDeadlinePassed(assignment.deadline);
@ -68,7 +68,7 @@ export const AssignmentColumns: ColumnDef<CourseAssignment>[] = [
}, },
{ {
accessorKey: 'marks_obtained', accessorKey: 'marks_obtained',
header: () => <div className="text-center">Obtained Marks</div>, header: () => <div className="text-center">Erhaltene Punkte</div>,
cell: ({ row }) => { cell: ({ row }) => {
const assignment = row.original; const assignment = row.original;
const hasSubmission = assignment.submissions && assignment.submissions.length > 0; const hasSubmission = assignment.submissions && assignment.submissions.length > 0;
@ -87,11 +87,11 @@ export const AssignmentColumns: ColumnDef<CourseAssignment>[] = [
<p className="font-semibold"> <p className="font-semibold">
{latestSubmission?.marks_obtained} / {totalMarks} {latestSubmission?.marks_obtained} / {totalMarks}
</p> </p>
{isLate && <p className="text-muted-foreground text-xs">(Late: Max {latestSubmission?.assignment?.late_total_mark})</p>} {isLate && <p className="text-muted-foreground text-xs">(Verspätet: Max {latestSubmission?.assignment?.late_total_mark})</p>}
</div> </div>
) : ( ) : (
<div> <div>
<p className="text-muted-foreground text-sm">Not Graded</p> <p className="text-muted-foreground text-sm">Nicht bewertet</p>
<p className="text-muted-foreground text-xs">Max: {totalMarks}</p> <p className="text-muted-foreground text-xs">Max: {totalMarks}</p>
</div> </div>
)} )}
@ -115,7 +115,7 @@ export const AssignmentColumns: ColumnDef<CourseAssignment>[] = [
}, },
{ {
id: 'actions', id: 'actions',
header: () => <div className="text-right">Action</div>, header: () => <div className="text-right">Aktion</div>,
cell: ({ row }) => { cell: ({ row }) => {
const assignment = row.original; const assignment = row.original;

View File

@ -21,12 +21,12 @@ const QuizIcon = ({ quiz, latestSubmission }: { quiz: SectionQuiz; latestSubmiss
return ( return (
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
{/* Quiz Icon */} {/* Quiz-Symbol */}
<div className="bg-primary/10 flex h-12 w-12 items-center justify-center rounded-lg"> <div className="bg-primary/10 flex h-12 w-12 items-center justify-center rounded-lg">
<ClipboardList className="text-primary h-6 w-6" /> <ClipboardList className="text-primary h-6 w-6" />
</div> </div>
{/* Quiz Info */} {/* Quiz-Info */}
<div className="flex-1"> <div className="flex-1">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<p className="text-primary text-base font-medium">{quiz.title}</p> <p className="text-primary text-base font-medium">{quiz.title}</p>
@ -37,7 +37,7 @@ const QuizIcon = ({ quiz, latestSubmission }: { quiz: SectionQuiz; latestSubmiss
)} )}
{!hasAttempted && ( {!hasAttempted && (
<Badge variant="destructive" className="text-xs"> <Badge variant="destructive" className="text-xs">
Not Submitted Nicht eingereicht
</Badge> </Badge>
)} )}
</div> </div>
@ -97,7 +97,7 @@ const QuizStatus = ({ quiz, completed }: Props) => {
lesson_id: quiz.id, lesson_id: quiz.id,
})} })}
> >
{'Take Quiz'} Quiz starten
</Link> </Link>
</Button> </Button>
)} )}
@ -112,7 +112,7 @@ const QuizStatus = ({ quiz, completed }: Props) => {
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
{/* Marks Display */} {/* Punkteanzeige */}
{hasAttempted && ( {hasAttempted && (
<div className="text-right"> <div className="text-right">
<p className="text-sm font-medium text-gray-500"> <p className="text-sm font-medium text-gray-500">

View File

@ -25,7 +25,7 @@ const CourseQuizzes = () => {
section.section_quizzes.map((quiz) => <QuizStatus key={quiz.id} quiz={quiz} completed={completed} />) section.section_quizzes.map((quiz) => <QuizStatus key={quiz.id} quiz={quiz} completed={completed} />)
) : ( ) : (
<div className="px-4 py-3 text-center"> <div className="px-4 py-3 text-center">
<p>There is no quiz added</p> <p>Kein Quiz vorhanden</p>
</div> </div>
)} )}
</AccordionContent> </AccordionContent>
@ -35,7 +35,7 @@ const CourseQuizzes = () => {
</Accordion> </Accordion>
) : ( ) : (
<div className="p-6 text-center"> <div className="p-6 text-center">
<p>There is no quiz added</p> <p>Kein Quiz vorhanden</p>
</div> </div>
)} )}
</> </>

View File

@ -10,21 +10,21 @@ const CourseResources = () => {
const { props } = usePage<StudentCourseProps>(); const { props } = usePage<StudentCourseProps>();
const { resources } = props; const { resources } = props;
// Function to format date in Bengali style if needed // Funktion zum Formatieren von Datum/Uhrzeit (bei Bedarf auf Deutsch)
const formatDate = (dateString: string) => { const formatDate = (dateString: string) => {
const date = new Date(dateString); const date = new Date(dateString);
return format(date, 'MMMM dd, yyyy, hh:mm a'); return format(date, 'MMMM dd, yyyy, hh:mm a');
}; };
// Helper to handle file download // Helferfunktion zum Herunterladen von Dateien
const handleDownload = async (resource: LessonResource, e: React.MouseEvent) => { const handleDownload = async (resource: LessonResource, e: React.MouseEvent) => {
e.preventDefault(); e.preventDefault();
try { try {
// For non-link resources, use the download endpoint // Für nicht-verlinkte Ressourcen den Download-Endpunkt verwenden
const url = route('resources.download', resource.id); const url = route('resources.download', resource.id);
window.open(url, '_blank'); window.open(url, '_blank');
} catch (error) { } catch (error) {
// Fallback to direct download if the endpoint fails // Fallback: Direktes Öffnen/Herunterladen, falls der Endpunkt fehlschlägt
window.open(resource.resource, '_blank'); window.open(resource.resource, '_blank');
} }
}; };
@ -34,12 +34,12 @@ const CourseResources = () => {
{resources && resources.length > 0 ? ( {resources && resources.length > 0 ? (
resources.map((section, sectionIndex) => ( resources.map((section, sectionIndex) => (
<Card key={section.id}> <Card key={section.id}>
{/* Module Header */} {/* Modul-Überschrift */}
<div className="bg-muted rounded-t-lg px-4 py-3"> <div className="bg-muted rounded-t-lg px-4 py-3">
<h3 className="text-lg font-semibold">Module: {section.title}</h3> <h3 className="text-lg font-semibold">Modul: {section.title}</h3>
</div> </div>
{/* Lessons Table */} {/* Lektionen-Tabelle */}
<div className="space-y-4 p-4"> <div className="space-y-4 p-4">
{section.section_lessons && section.section_lessons.length > 0 ? ( {section.section_lessons && section.section_lessons.length > 0 ? (
section.section_lessons.map((lesson) => section.section_lessons.map((lesson) =>
@ -48,7 +48,7 @@ const CourseResources = () => {
{/* Lesson Title */} {/* Lesson Title */}
<div className="p-4"> <div className="p-4">
<p className="text-base font-medium"> <p className="text-base font-medium">
<span className="font-semibold">Lesson:</span> {lesson.title} <span className="font-semibold">Lektion:</span> {lesson.title}
</p> </p>
</div> </div>
@ -57,9 +57,9 @@ const CourseResources = () => {
<Table> <Table>
<TableHeader className="bg-muted/50"> <TableHeader className="bg-muted/50">
<TableRow> <TableRow>
<TableHead className="px-4 font-semibold">Title</TableHead> <TableHead className="px-4 font-semibold">Titel</TableHead>
<TableHead className="px-4 font-semibold">Date & Time</TableHead> <TableHead className="px-4 font-semibold">Datum & Uhrzeit</TableHead>
<TableHead className="px-4 text-right font-semibold">Action</TableHead> <TableHead className="px-4 text-right font-semibold">Aktion</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@ -73,13 +73,13 @@ const CourseResources = () => {
<Button asChild size="sm" variant="secondary"> <Button asChild size="sm" variant="secondary">
<a target="_blank" href={resource.resource}> <a target="_blank" href={resource.resource}>
<ExternalLink className="h-3 w-3" /> <ExternalLink className="h-3 w-3" />
Check Ansehen
</a> </a>
</Button> </Button>
) : ( ) : (
<Button size="sm" variant="secondary" onClick={(e) => handleDownload(resource, e)}> <Button size="sm" variant="secondary" onClick={(e) => handleDownload(resource, e)}>
<Download className="h-3 w-3" /> <Download className="h-3 w-3" />
Download Herunterladen
</Button> </Button>
)} )}
</div> </div>
@ -93,14 +93,14 @@ const CourseResources = () => {
) : null, ) : null,
) )
) : ( ) : (
<div className="text-muted-foreground py-8 text-center">No lessons found in this module.</div> <div className="text-muted-foreground py-8 text-center">Keine Lektionen in diesem Modul gefunden.</div>
)} )}
</div> </div>
</Card> </Card>
)) ))
) : ( ) : (
<div className="py-12 text-center"> <div className="py-12 text-center">
<p className="text-muted-foreground text-lg">No resources available for this course yet.</p> <p className="text-muted-foreground text-lg">Für diesen Kurs sind noch keine Ressourcen verfügbar.</p>
</div> </div>
)} )}
</div> </div>

View File

@ -25,7 +25,7 @@ const Quizzes = () => {
section.section_quizzes.map((quiz) => <QuizStatus key={quiz.id} quiz={quiz} completed={completed} />) section.section_quizzes.map((quiz) => <QuizStatus key={quiz.id} quiz={quiz} completed={completed} />)
) : ( ) : (
<div className="px-4 py-3 text-center"> <div className="px-4 py-3 text-center">
<p>There is no quiz added</p> <p>Kein Quiz vorhanden</p>
</div> </div>
)} )}
</AccordionContent> </AccordionContent>
@ -35,7 +35,7 @@ const Quizzes = () => {
</Accordion> </Accordion>
) : ( ) : (
<div className="p-6 text-center"> <div className="p-6 text-center">
<p>There is no quiz added</p> <p>Kein Quiz vorhanden</p>
</div> </div>
)} )}
</> </>

View File

@ -10,21 +10,21 @@ const Resources = () => {
const { props } = usePage<StudentCourseProps>(); const { props } = usePage<StudentCourseProps>();
const { resources } = props; const { resources } = props;
// Function to format date in Bengali style if needed // Funktion zum Formatieren von Datum/Uhrzeit (bei Bedarf auf Deutsch)
const formatDate = (dateString: string) => { const formatDate = (dateString: string) => {
const date = new Date(dateString); const date = new Date(dateString);
return format(date, 'MMMM dd, yyyy, hh:mm a'); return format(date, 'MMMM dd, yyyy, hh:mm a');
}; };
// Helper to handle file download // Helferfunktion zum Herunterladen von Dateien
const handleDownload = async (resource: LessonResource, e: React.MouseEvent) => { const handleDownload = async (resource: LessonResource, e: React.MouseEvent) => {
e.preventDefault(); e.preventDefault();
try { try {
// For non-link resources, use the download endpoint // Für nicht-verlinkte Ressourcen den Download-Endpunkt verwenden
const url = route('resources.download', resource.id); const url = route('resources.download', resource.id);
window.open(url, '_blank'); window.open(url, '_blank');
} catch (error) { } catch (error) {
// Fallback to direct download if the endpoint fails // Fallback: Direktes Öffnen/Herunterladen, falls der Endpunkt fehlschlägt
window.open(resource.resource, '_blank'); window.open(resource.resource, '_blank');
} }
}; };
@ -34,12 +34,12 @@ const Resources = () => {
{resources && resources.length > 0 ? ( {resources && resources.length > 0 ? (
resources.map((section, sectionIndex) => ( resources.map((section, sectionIndex) => (
<Card key={section.id}> <Card key={section.id}>
{/* Module Header */} {/* Modul-Überschrift */}
<div className="bg-muted rounded-t-lg px-4 py-3"> <div className="bg-muted rounded-t-lg px-4 py-3">
<h3 className="text-lg font-semibold">Module: {section.title}</h3> <h3 className="text-lg font-semibold">Modul: {section.title}</h3>
</div> </div>
{/* Lessons Table */} {/* Lektionen-Tabelle */}
<div className="space-y-4 p-4"> <div className="space-y-4 p-4">
{section.section_lessons && section.section_lessons.length > 0 ? ( {section.section_lessons && section.section_lessons.length > 0 ? (
section.section_lessons.map((lesson) => section.section_lessons.map((lesson) =>
@ -48,7 +48,7 @@ const Resources = () => {
{/* Lesson Title */} {/* Lesson Title */}
<div className="p-4"> <div className="p-4">
<p className="text-base font-medium"> <p className="text-base font-medium">
<span className="font-semibold">Lesson:</span> {lesson.title} <span className="font-semibold">Lektion:</span> {lesson.title}
</p> </p>
</div> </div>
@ -57,9 +57,9 @@ const Resources = () => {
<Table> <Table>
<TableHeader className="bg-muted/50"> <TableHeader className="bg-muted/50">
<TableRow> <TableRow>
<TableHead className="px-4 font-semibold">Title</TableHead> <TableHead className="px-4 font-semibold">Titel</TableHead>
<TableHead className="px-4 font-semibold">Date & Time</TableHead> <TableHead className="px-4 font-semibold">Datum & Uhrzeit</TableHead>
<TableHead className="px-4 text-right font-semibold">Action</TableHead> <TableHead className="px-4 text-right font-semibold">Aktion</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@ -73,13 +73,13 @@ const Resources = () => {
<Button asChild size="sm" variant="secondary"> <Button asChild size="sm" variant="secondary">
<a target="_blank" href={resource.resource}> <a target="_blank" href={resource.resource}>
<ExternalLink className="h-3 w-3" /> <ExternalLink className="h-3 w-3" />
Check Ansehen
</a> </a>
</Button> </Button>
) : ( ) : (
<Button size="sm" variant="secondary" onClick={(e) => handleDownload(resource, e)}> <Button size="sm" variant="secondary" onClick={(e) => handleDownload(resource, e)}>
<Download className="h-3 w-3" /> <Download className="h-3 w-3" />
Download Herunterladen
</Button> </Button>
)} )}
</div> </div>
@ -93,14 +93,14 @@ const Resources = () => {
) : null, ) : null,
) )
) : ( ) : (
<div className="text-muted-foreground py-8 text-center">No lessons found in this module.</div> <div className="text-muted-foreground py-8 text-center">Keine Lektionen in diesem Modul gefunden.</div>
)} )}
</div> </div>
</Card> </Card>
)) ))
) : ( ) : (
<div className="py-12 text-center"> <div className="py-12 text-center">
<p className="text-muted-foreground text-lg">No resources available for this course yet.</p> <p className="text-muted-foreground text-lg">Für diesen Kurs sind noch keine Ressourcen verfügbar.</p>
</div> </div>
)} )}
</div> </div>