some bugfixes
All checks were successful
Build & Push Docker Image / docker (push) Successful in 1m50s
All checks were successful
Build & Push Docker Image / docker (push) Successful in 1m50s
This commit is contained in:
parent
da407e95e8
commit
60cc9db469
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user