import React, { useMemo, useEffect, useState } from 'react'; import ReactConfetti from 'react-confetti'; import { Trophy, ArrowLeft, BookOpen, Target, Download } from 'lucide-react'; import Link from 'next/link'; import { getUriWithOrg } from '@services/config/config'; import { getCourseThumbnailMediaDirectory } from '@services/media/media'; import { useWindowSize } from 'usehooks-ts'; import { useOrg } from '@components/Contexts/OrgContext'; import { useLHSession } from '@components/Contexts/LHSessionContext'; import { getUserCertificates } from '@services/courses/certifications'; import CertificatePreview from '@components/Dashboard/Pages/Course/EditCourseCertification/CertificatePreview'; import html2canvas from 'html2canvas'; import jsPDF from 'jspdf'; import QRCode from 'qrcode'; interface CourseEndViewProps { courseName: string; orgslug: string; courseUuid: string; thumbnailImage: string; course: any; trailData: any; } const CourseEndView: React.FC = ({ courseName, orgslug, courseUuid, thumbnailImage, course, trailData }) => { const { width, height } = useWindowSize(); const org = useOrg() as any; const session = useLHSession() as any; const [userCertificate, setUserCertificate] = useState(null); const [isLoadingCertificate, setIsLoadingCertificate] = useState(false); const [certificateError, setCertificateError] = useState(null); const qrCodeLink = getUriWithOrg(orgslug, `/certificates/${userCertificate?.certificate_user.user_certification_uuid}/verify`); // Check if course is actually completed const isCourseCompleted = useMemo(() => { if (!trailData || !course) return false; // Flatten all activities const allActivities = course.chapters.flatMap((chapter: any) => chapter.activities.map((activity: any) => ({ ...activity, chapterId: chapter.id })) ); // Check if all activities are completed const isActivityDone = (activity: any) => { const cleanCourseUuid = course.course_uuid?.replace('course_', ''); const run = trailData?.runs?.find( (run: any) => { const cleanRunCourseUuid = run.course?.course_uuid?.replace('course_', ''); return cleanRunCourseUuid === cleanCourseUuid; } ); if (run) { return run.steps.find( (step: any) => step.activity_id === activity.id && step.complete === true ); } return false; }; const totalActivities = allActivities.length; const completedActivities = allActivities.filter((activity: any) => isActivityDone(activity)).length; return totalActivities > 0 && completedActivities === totalActivities; }, [trailData, course]); // Fetch user certificate when course is completed useEffect(() => { const fetchUserCertificate = async () => { if (!isCourseCompleted) return; if (!session?.data?.tokens?.access_token) { setCertificateError('Authentication required to view certificate'); return; } setIsLoadingCertificate(true); setCertificateError(null); try { const cleanCourseUuid = courseUuid.replace('course_', ''); const result = await getUserCertificates( `course_${cleanCourseUuid}`, session.data.tokens.access_token ); if (result.success && result.data && result.data.length > 0) { setUserCertificate(result.data[0]); } else { setCertificateError('No certificate found for this course'); } } catch (error) { console.error('Error fetching user certificate:', error); setCertificateError('Failed to load certificate. Please try again later.'); } finally { setIsLoadingCertificate(false); } }; fetchUserCertificate(); }, [isCourseCompleted, courseUuid, session?.data?.tokens?.access_token]); // Generate PDF using canvas const downloadCertificate = async () => { if (!userCertificate) return; try { // Create a temporary div for the certificate const certificateDiv = document.createElement('div'); certificateDiv.style.position = 'absolute'; certificateDiv.style.left = '-9999px'; certificateDiv.style.top = '0'; certificateDiv.style.width = '800px'; certificateDiv.style.height = '600px'; certificateDiv.style.background = 'white'; certificateDiv.style.padding = '40px'; certificateDiv.style.fontFamily = 'Arial, sans-serif'; certificateDiv.style.textAlign = 'center'; certificateDiv.style.display = 'flex'; certificateDiv.style.flexDirection = 'column'; certificateDiv.style.justifyContent = 'center'; certificateDiv.style.alignItems = 'center'; certificateDiv.style.position = 'relative'; certificateDiv.style.overflow = 'hidden'; // Get theme colors based on pattern const getPatternTheme = (pattern: string) => { switch (pattern) { case 'royal': return { primary: '#b45309', secondary: '#d97706', icon: '#d97706' }; case 'tech': return { primary: '#0e7490', secondary: '#0891b2', icon: '#0891b2' }; case 'nature': return { primary: '#15803d', secondary: '#16a34a', icon: '#16a34a' }; case 'geometric': return { primary: '#7c3aed', secondary: '#9333ea', icon: '#9333ea' }; case 'vintage': return { primary: '#c2410c', secondary: '#ea580c', icon: '#ea580c' }; case 'waves': return { primary: '#1d4ed8', secondary: '#2563eb', icon: '#2563eb' }; case 'minimal': return { primary: '#374151', secondary: '#4b5563', icon: '#4b5563' }; case 'professional': return { primary: '#334155', secondary: '#475569', icon: '#475569' }; case 'academic': return { primary: '#3730a3', secondary: '#4338ca', icon: '#4338ca' }; case 'modern': return { primary: '#1d4ed8', secondary: '#2563eb', icon: '#2563eb' }; default: return { primary: '#374151', secondary: '#4b5563', icon: '#4b5563' }; } }; const theme = getPatternTheme(userCertificate.certification.config.certificate_pattern); const certificateId = userCertificate.certificate_user.user_certification_uuid; const qrCodeData = qrCodeLink; // Generate QR code const qrCodeDataUrl = await QRCode.toDataURL(qrCodeData, { width: 120, margin: 2, color: { dark: '#000000', light: '#FFFFFF' }, errorCorrectionLevel: 'M', type: 'image/png' }); // Create certificate content certificateDiv.innerHTML = `
ID: ${certificateId}
QR Code
Certificate
🏆
${userCertificate.certification.config.certification_name}
${userCertificate.certification.config.certification_description || 'This is to certify that the course has been successfully completed.'}
${userCertificate.certification.config.certification_type === 'completion' ? 'Course Completion' : userCertificate.certification.config.certification_type === 'achievement' ? 'Achievement Based' : userCertificate.certification.config.certification_type === 'assessment' ? 'Assessment Based' : userCertificate.certification.config.certification_type === 'participation' ? 'Participation' : userCertificate.certification.config.certification_type === 'mastery' ? 'Skill Mastery' : userCertificate.certification.config.certification_type === 'professional' ? 'Professional Development' : userCertificate.certification.config.certification_type === 'continuing' ? 'Continuing Education' : userCertificate.certification.config.certification_type === 'workshop' ? 'Workshop Attendance' : userCertificate.certification.config.certification_type === 'specialization' ? 'Specialization' : 'Course Completion'}
Certificate ID: ${certificateId}
Awarded: ${new Date(userCertificate.certificate_user.created_at).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}
${userCertificate.certification.config.certificate_instructor ? `
Instructor: ${userCertificate.certification.config.certificate_instructor}
` : '' }
This certificate can be verified at ${qrCodeLink}
`; // Add to document temporarily document.body.appendChild(certificateDiv); // Convert to canvas const canvas = await html2canvas(certificateDiv, { width: 800, height: 600, scale: 2, // Higher resolution useCORS: true, allowTaint: true, backgroundColor: '#ffffff' }); // Remove temporary div document.body.removeChild(certificateDiv); // Create PDF const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF('landscape', 'mm', 'a4'); // Calculate dimensions to center the certificate const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const imgWidth = 280; // mm const imgHeight = 210; // mm // Center the image const x = (pdfWidth - imgWidth) / 2; const y = (pdfHeight - imgHeight) / 2; pdf.addImage(imgData, 'PNG', x, y, imgWidth, imgHeight); // Save the PDF const fileName = `${userCertificate.certification.config.certification_name.replace(/[^a-zA-Z0-9]/g, '_')}_Certificate.pdf`; pdf.save(fileName); } catch (error) { console.error('Error generating PDF:', error); alert('Failed to generate PDF. Please try again.'); } }; // Calculate progress for incomplete courses const progressInfo = useMemo(() => { if (!trailData || !course || isCourseCompleted) return null; const allActivities = course.chapters.flatMap((chapter: any) => chapter.activities.map((activity: any) => ({ ...activity, chapterId: chapter.id })) ); const isActivityDone = (activity: any) => { const cleanCourseUuid = course.course_uuid?.replace('course_', ''); const run = trailData?.runs?.find( (run: any) => { const cleanRunCourseUuid = run.course?.course_uuid?.replace('course_', ''); return cleanRunCourseUuid === cleanCourseUuid; } ); if (run) { return run.steps.find( (step: any) => step.activity_id === activity.id && step.complete === true ); } return false; }; const totalActivities = allActivities.length; const completedActivities = allActivities.filter((activity: any) => isActivityDone(activity)).length; const progressPercentage = Math.round((completedActivities / totalActivities) * 100); return { completed: completedActivities, total: totalActivities, percentage: progressPercentage }; }, [trailData, course, isCourseCompleted]); if (isCourseCompleted) { // Show congratulations for completed course return (
{thumbnailImage && ( {courseName} )}

Congratulations! 🎉

You've successfully completed {courseName}

Your dedication and hard work have paid off. You've mastered all the content in this course.

{/* Certificate Display */} {isLoadingCertificate ? (
Loading your certificate...
) : certificateError ? (

{certificateError}

) : userCertificate ? (

Your Certificate

) : (

No certificate is available for this course. Contact your instructor for more information.

)}
Back to Course
); } else { // Show progress and encouragement for incomplete course return (
{thumbnailImage && ( {courseName} )}

Keep Going! 💪

You're making great progress in {courseName}

{progressInfo && (
Course Progress
Progress {progressInfo.percentage}%
{progressInfo.completed} of {progressInfo.total} activities completed
)}

You're doing great! Complete the remaining activities to unlock your course completion certificate.

Continue Learning
); } }; export default CourseEndView;