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

This commit is contained in:
Ahmed Darrazi 2025-12-18 22:57:40 +01:00
parent da407e95e8
commit 60cc9db469
3 changed files with 40 additions and 40 deletions

View File

@ -20,7 +20,7 @@ const CertificateGenerator = () => {
const handleGenerateCertificate = async () => { const handleGenerateCertificate = async () => {
if (!studentName || !courseName || !completionDate) { if (!studentName || !courseName || !completionDate) {
toast.error('Please fill in all required fields.'); toast.error('Bitte fülle alle Pflichtfelder aus.');
return; return;
} }
@ -29,7 +29,7 @@ const CertificateGenerator = () => {
// Simulate certificate generation // Simulate certificate generation
setTimeout(() => { setTimeout(() => {
setIsGenerating(false); setIsGenerating(false);
toast.success('Your course completion certificate has been created successfully.'); toast.success('Dein Kursabschlusszertifikat wurde erfolgreich erstellt.');
}, 2000); }, 2000);
}; };
@ -73,7 +73,7 @@ const CertificateGenerator = () => {
document.body.removeChild(a); document.body.removeChild(a);
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
toast.success('Your PNG certificate has been saved to your downloads folder.'); toast.success('Dein PNG-Zertifikat wurde in deinem Download-Ordner gespeichert.');
}, 'image/png'); }, 'image/png');
}; };
@ -107,7 +107,7 @@ const CertificateGenerator = () => {
// Save the PDF // Save the PDF
pdf.save(`${studentName}_${courseName}_Certificate.pdf`); pdf.save(`${studentName}_${courseName}_Certificate.pdf`);
toast.success('Your PDF certificate has been saved to your downloads folder.'); toast.success('Dein PDF-Zertifikat wurde in deinem Download-Ordner gespeichert.');
}; };
const drawCertificate = (ctx: CanvasRenderingContext2D, dimensions: { width: number; height: number }) => { const drawCertificate = (ctx: CanvasRenderingContext2D, dimensions: { width: number; height: number }) => {
@ -135,7 +135,7 @@ const CertificateGenerator = () => {
// Title // Title
ctx.font = 'bold 42px serif'; ctx.font = 'bold 42px serif';
ctx.fillText('Certificate of Completion', dimensions.width / 2, 120); ctx.fillText('Abschlusszertifikat', dimensions.width / 2, 120);
// Decorative line under title // Decorative line under title
ctx.strokeStyle = '#f59e0b'; ctx.strokeStyle = '#f59e0b';
@ -148,7 +148,7 @@ const CertificateGenerator = () => {
// "This is to certify that" // "This is to certify that"
ctx.font = '22px serif'; ctx.font = '22px serif';
ctx.fillStyle = '#4b5563'; ctx.fillStyle = '#4b5563';
ctx.fillText('This is to certify that', dimensions.width / 2, 190); ctx.fillText('Hiermit wird bescheinigt, dass', dimensions.width / 2, 190);
// Student name with underline // Student name with underline
ctx.font = 'bold 36px serif'; ctx.font = 'bold 36px serif';
@ -167,7 +167,7 @@ const CertificateGenerator = () => {
// "has successfully completed the course" // "has successfully completed the course"
ctx.font = '22px serif'; ctx.font = '22px serif';
ctx.fillStyle = '#4b5563'; ctx.fillStyle = '#4b5563';
ctx.fillText('has successfully completed the course', dimensions.width / 2, 320); ctx.fillText('den Kurs erfolgreich abgeschlossen hat', dimensions.width / 2, 320);
// Course name // Course name
ctx.font = 'bold 28px serif'; ctx.font = 'bold 28px serif';
@ -177,7 +177,7 @@ const CertificateGenerator = () => {
// Completion date // Completion date
ctx.font = '18px serif'; ctx.font = '18px serif';
ctx.fillStyle = '#6b7280'; ctx.fillStyle = '#6b7280';
ctx.fillText(`Completed on: ${completionDate}`, dimensions.width / 2, 430); ctx.fillText(`Abgeschlossen am: ${completionDate}`, dimensions.width / 2, 430);
// Footer // Footer
ctx.font = '16px serif'; ctx.font = '16px serif';
@ -190,8 +190,8 @@ const CertificateGenerator = () => {
return ( return (
<div className="space-y-8"> <div className="space-y-8">
<div className="text-center"> <div className="text-center">
<h1 className="mb-4 text-4xl font-bold text-gray-800">Course Certificate Generator</h1> <h1 className="mb-4 text-4xl font-bold text-gray-800">Zertifikatsgenerator</h1>
<p className="text-muted-foreground text-lg">Generate your official course completion certificate</p> <p className="text-muted-foreground text-lg">Erstelle dein offizielles Kursabschlusszertifikat</p>
</div> </div>
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2"> <div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
@ -200,23 +200,23 @@ const CertificateGenerator = () => {
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-2"> <CardTitle className="flex items-center gap-2">
<Award className="h-5 w-5 text-amber-600" /> <Award className="h-5 w-5 text-amber-600" />
Certificate Details Zertifikatsdetails
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-6"> <CardContent className="space-y-6">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="studentName">Student Name *</Label> <Label htmlFor="studentName">Name des Teilnehmers *</Label>
<Input <Input
id="studentName" id="studentName"
value={studentName} value={studentName}
onChange={(e) => setStudentName(e.target.value)} onChange={(e) => setStudentName(e.target.value)}
placeholder="Enter your full name" placeholder="Gib deinen vollständigen Namen ein"
/> />
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="courseName">Course Name *</Label> <Label htmlFor="courseName">Kursname *</Label>
<Input id="courseName" value={courseName} onChange={(e) => setCourseName(e.target.value)} placeholder="Enter the course name" /> <Input id="courseName" value={courseName} onChange={(e) => setCourseName(e.target.value)} placeholder="Gib den Kursnamen ein" />
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
@ -232,33 +232,33 @@ const CertificateGenerator = () => {
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
<Label>Certificate Size</Label> <Label>Zertifikatsgröße</Label>
<Select value={certificateSize} onValueChange={setCertificateSize}> <Select value={certificateSize} onValueChange={setCertificateSize}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Select certificate size" /> <SelectValue placeholder="Wähle Zertifikatsgröße" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="standard">Standard (800x600)</SelectItem> <SelectItem value="standard">Standard (800×600)</SelectItem>
<SelectItem value="a4">A4 Landscape (842x595)</SelectItem> <SelectItem value="a4">A4 Querformat (842×595)</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
<Label>Download Format</Label> <Label>Download-Format</Label>
<RadioGroup value={downloadFormat} onValueChange={setDownloadFormat} className="flex space-x-6"> <RadioGroup value={downloadFormat} onValueChange={setDownloadFormat} className="flex space-x-6">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<RadioGroupItem className="cursor-pointer" value="png" id="png" /> <RadioGroupItem className="cursor-pointer" value="png" id="png" />
<Label htmlFor="png" className="flex cursor-pointer items-center gap-2"> <Label htmlFor="png" className="flex cursor-pointer items-center gap-2">
<FileImage className="h-4 w-4" /> <FileImage className="h-4 w-4" />
PNG Image PNG-Bild
</Label> </Label>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<RadioGroupItem className="cursor-pointer" value="pdf" id="pdf" /> <RadioGroupItem className="cursor-pointer" value="pdf" id="pdf" />
<Label htmlFor="pdf" className="flex cursor-pointer items-center gap-2"> <Label htmlFor="pdf" className="flex cursor-pointer items-center gap-2">
<FileText className="h-4 w-4" /> <FileText className="h-4 w-4" />
PDF Document PDF-Dokument
</Label> </Label>
</div> </div>
</RadioGroup> </RadioGroup>
@ -269,12 +269,12 @@ const CertificateGenerator = () => {
{isGenerating ? ( {isGenerating ? (
<> <>
<div className="mr-2 h-4 w-4 animate-spin rounded-full border-b-2 border-white" /> <div className="mr-2 h-4 w-4 animate-spin rounded-full border-b-2 border-white" />
Generating Certificate... Zertifikat wird erstellt...
</> </>
) : ( ) : (
<> <>
<Award className="mr-2 h-4 w-4" /> <Award className="mr-2 h-4 w-4" />
Generate Certificate Zertifikat erstellen
</> </>
)} )}
</Button> </Button>
@ -284,7 +284,7 @@ const CertificateGenerator = () => {
{/* Preview Section */} {/* Preview Section */}
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Certificate Preview</CardTitle> <CardTitle>Zertifikatsvorschau</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div <div
@ -297,26 +297,26 @@ const CertificateGenerator = () => {
<div className="relative z-10"> <div className="relative z-10">
<div className="mb-6"> <div className="mb-6">
<Award className="mx-auto mb-3 h-12 w-12 text-amber-600" /> <Award className="mx-auto mb-3 h-12 w-12 text-amber-600" />
<h2 className="mb-2 font-serif text-2xl font-bold text-gray-800">Certificate of Completion</h2> <h2 className="mb-2 font-serif text-2xl font-bold text-gray-800">Abschlusszertifikat</h2>
<div className="mx-auto h-0.5 w-32 bg-amber-400"></div> <div className="mx-auto h-0.5 w-32 bg-amber-400"></div>
</div> </div>
<div className="space-y-4 text-gray-700"> <div className="space-y-4 text-gray-700">
<p className="font-serif text-lg">This is to certify that</p> <p className="font-serif text-lg">Hiermit wird bescheinigt, dass</p>
<div className="relative"> <div className="relative">
<p className="mx-8 pb-2 font-serif text-2xl font-bold text-indigo-800">{studentName || 'Student Name'}</p> <p className="mx-8 pb-2 font-serif text-2xl font-bold text-indigo-800">{studentName || 'Student Name'}</p>
<div className="absolute bottom-0 left-1/2 h-0.5 w-48 -translate-x-1/2 transform bg-amber-400"></div> <div className="absolute bottom-0 left-1/2 h-0.5 w-48 -translate-x-1/2 transform bg-amber-400"></div>
</div> </div>
<p className="font-serif text-lg">has successfully completed the course</p> <p className="font-serif text-lg">den Kurs erfolgreich abgeschlossen hat</p>
<p className="font-serif text-xl font-semibold text-indigo-700">{courseName || 'Course Name'}</p> <p className="font-serif text-xl font-semibold text-indigo-700">{courseName || 'Kursname'}</p>
<div className="mt-6 flex items-center justify-center gap-2"> <div className="mt-6 flex items-center justify-center gap-2">
<Calendar className="text-muted-foreground h-4 w-4" /> <Calendar className="text-muted-foreground h-4 w-4" />
<p className="text-muted-foreground font-serif text-sm">Completed on: {completionDate || 'Date'}</p> <p className="text-muted-foreground font-serif text-sm">Abgeschlossen am: {completionDate || 'Datum'}</p>
</div> </div>
</div> </div>
<div className="mt-6 border-t border-amber-400 pt-4"> <div className="mt-6 border-t border-amber-400 pt-4">
<p className="font-serif text-sm text-gray-500">Authorized Certificate of Achievement</p> <p className="font-serif text-sm text-gray-500">Autorisierte Leistungsurkunde</p>
</div> </div>
</div> </div>
</div> </div>
@ -324,7 +324,7 @@ const CertificateGenerator = () => {
{studentName && courseName && completionDate && ( {studentName && courseName && completionDate && (
<Button variant="outline" className="mt-4 w-full" onClick={handleDownloadCertificate}> <Button variant="outline" className="mt-4 w-full" onClick={handleDownloadCertificate}>
<Download className="mr-2 h-4 w-4" /> <Download className="mr-2 h-4 w-4" />
Download as {downloadFormat.toUpperCase()} Herunterladen als {downloadFormat.toUpperCase()}
</Button> </Button>
)} )}
</CardContent> </CardContent>

View File

@ -28,7 +28,7 @@ interface ContentListProps {
const ContentList = ({ completedContents, courseCompletion }: ContentListProps) => { const ContentList = ({ completedContents, courseCompletion }: ContentListProps) => {
const { props } = usePage<CoursePlayerProps>(); const { props } = usePage<CoursePlayerProps>();
const { course, zoomConfig, section, watchHistory, translate, direction } = props; const { course, zoomConfig, section, watchHistory, translate, direction } = props;
const { button, common } = translate; const { button, common, frontend } = translate;
// Get live classes from course data // Get live classes from course data
const liveClasses = course.live_classes || []; const liveClasses = course.live_classes || [];
@ -119,7 +119,7 @@ const ContentList = ({ completedContents, courseCompletion }: ContentListProps)
})} })}
> >
<Button className="w-full" variant="secondary" size="lg" disabled={courseCompletion.percentage !== '100.00'}> <Button className="w-full" variant="secondary" size="lg" disabled={courseCompletion.percentage !== '100.00'}>
Course Certificate {frontend.course_certificate}
</Button> </Button>
</Link> </Link>
</div> </div>
@ -127,11 +127,11 @@ const ContentList = ({ completedContents, courseCompletion }: ContentListProps)
<div> <div>
{!watchHistory.next_watching_id ? ( {!watchHistory.next_watching_id ? (
<Button className="w-full" variant="secondary" size="lg" onClick={finishCourseHandler}> <Button className="w-full" variant="secondary" size="lg" onClick={finishCourseHandler}>
Finish Course Kurs abschließen
</Button> </Button>
) : ( ) : (
<Button className="w-full" variant="secondary" size="lg" disabled> <Button className="w-full" variant="secondary" size="lg" disabled>
Finish Course Kurs abschließen
</Button> </Button>
)} )}
</div> </div>

View File

@ -117,7 +117,7 @@ const CoursePreview = () => {
<Mail className="h-5 w-5" /> <Mail className="h-5 w-5" />
{frontend.certificate_included} {frontend.certificate_included}
</span> </span>
<span>Yes</span> <span>{course.certificate_included ? 'Ja' : 'Nein'}</span>
</div> </div>
</div> </div>
</div> </div>