dashboard & cource certificate Block chain

This commit is contained in:
5t4l1n
2025-07-29 20:43:52 +05:30
parent 6376105b1d
commit a3520a3d67
6 changed files with 1224 additions and 1593 deletions
+134 -15
View File
@@ -10,18 +10,31 @@ interface Certificate {
share_code: string
user_name: string
student_name: string
studentName?: string // camelCase variant
userName?: string // camelCase variant
course_title: string
courseTitle?: string // camelCase variant
mentor_name: string
instructor_name: string
instructorName?: string // camelCase variant
mentorName?: string // camelCase variant
completion_date: string
completionDate?: string // camelCase variant
wallet_address?: string
walletAddress?: string // camelCase variant
issued_by: string
issuedBy?: string // camelCase variant
view_count: number
viewCount?: number // camelCase variant
blockchain_hash?: string
blockchainHash?: string // camelCase variant
public_url?: string
publicUrl?: string // camelCase variant
verification_url?: string
is_verified: boolean
isVerified?: boolean // camelCase variant
is_revoked: boolean
isRevoked?: boolean // camelCase variant
}
export default function CertificatePage() {
@@ -55,8 +68,23 @@ export default function CertificatePage() {
if (response.ok) {
const data = await response.json()
console.log('🔍 Verify endpoint response:', data)
if (data.success && data.verified) {
console.log('✅ Found certificate by verify endpoint')
console.log('🎓 Student name fields:', {
student_name: data.certificate?.student_name,
user_name: data.certificate?.user_name,
studentName: data.certificate?.studentName,
userName: data.certificate?.userName
})
console.log('👨‍🏫 Instructor name fields:', {
instructor_name: data.certificate?.instructor_name,
mentor_name: data.certificate?.mentor_name,
instructorName: data.certificate?.instructorName,
mentorName: data.certificate?.mentorName
})
setCertificate(data.certificate)
setLoading(false)
return
@@ -73,8 +101,23 @@ export default function CertificatePage() {
if (response.ok) {
const data = await response.json()
console.log('🔍 Direct endpoint response:', data)
if (data.success) {
console.log('✅ Found certificate by direct endpoint')
console.log('🎓 Student name fields:', {
student_name: data.certificate?.student_name,
user_name: data.certificate?.user_name,
studentName: data.certificate?.studentName,
userName: data.certificate?.userName
})
console.log('👨‍🏫 Instructor name fields:', {
instructor_name: data.certificate?.instructor_name,
mentor_name: data.certificate?.mentor_name,
instructorName: data.certificate?.instructorName,
mentorName: data.certificate?.mentorName
})
setCertificate(data.certificate)
setLoading(false)
return
@@ -95,15 +138,62 @@ export default function CertificatePage() {
}
}
// ✅ FIXED: Helper functions to get names with multiple fallbacks
const getStudentName = () => {
if (!certificate) return 'Student Name Missing'
const name = certificate.student_name ||
certificate.user_name ||
certificate.studentName ||
certificate.userName ||
'Student Name Missing'
console.log('🎓 Final student name:', name)
return name
}
const getInstructorName = () => {
if (!certificate) return 'OpenLearnX Instructor'
const name = certificate.instructor_name ||
certificate.mentor_name ||
certificate.instructorName ||
certificate.mentorName ||
'OpenLearnX Instructor'
console.log('👨‍🏫 Final instructor name:', name)
return name
}
const getCourseTitle = () => {
if (!certificate) return 'Course Title Missing'
return certificate.course_title ||
certificate.courseTitle ||
'Course Title Missing'
}
const getCompletionDate = () => {
if (!certificate) return new Date()
const dateStr = certificate.completion_date || certificate.completionDate || new Date().toISOString()
return new Date(dateStr)
}
const handleDownloadPDF = () => {
if (!certificate) return
try {
const studentName = getStudentName()
const instructorName = getInstructorName()
const courseTitle = getCourseTitle()
const completionDate = getCompletionDate()
const certificateHTML = `
<!DOCTYPE html>
<html>
<head>
<title>Certificate - ${certificate.user_name}</title>
<title>Certificate - ${studentName}</title>
<meta charset="UTF-8">
<style>
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Inter:wght@400;500;600&display=swap');
@@ -192,13 +282,13 @@ export default function CertificatePage() {
<div style="font-size: 18px; color: #6b7280; margin-bottom: 30px;">This is to certify that</div>
<div class="student-name">${certificate.user_name}</div>
<div class="student-name">${studentName}</div>
<div style="font-size: 18px; color: #6b7280; margin-bottom: 20px;">has successfully completed the course</div>
<div class="course-title">"${certificate.course_title}"</div>
<div class="course-title">"${courseTitle}"</div>
<div style="font-size: 16px; color: #374151; margin: 20px 0;">
✅ Completed on: ${new Date(certificate.completion_date).toLocaleDateString('en-US', {
✅ Completed on: ${completionDate.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
@@ -207,7 +297,7 @@ export default function CertificatePage() {
<div class="mentor-section">
<div style="width: 200px; height: 2px; background: #6b7280; margin: 0 auto 10px auto;"></div>
<div class="mentor-name">${certificate.mentor_name}</div>
<div class="mentor-name">${instructorName}</div>
<div style="font-size: 14px; color: #6b7280; margin-top: 5px;">Course Instructor</div>
</div>
@@ -247,13 +337,16 @@ export default function CertificatePage() {
const handleShare = async () => {
if (!certificate) return
const shareText = `🎓 Check out my certificate of completion for "${certificate.course_title}" from OpenLearnX!\n\nStudent: ${certificate.user_name}\nCertificate ID: ${certificate.certificate_id}\n\n#OpenLearnX #Certificate #Learning`
const studentName = getStudentName()
const courseTitle = getCourseTitle()
const shareText = `🎓 Check out my certificate of completion for "${courseTitle}" from OpenLearnX!\n\nStudent: ${studentName}\nCertificate ID: ${certificate.certificate_id}\n\n#OpenLearnX #Certificate #Learning`
const shareUrl = window.location.href
if (navigator.share) {
try {
await navigator.share({
title: `Certificate - ${certificate.course_title}`,
title: `Certificate - ${courseTitle}`,
text: shareText,
url: shareUrl
})
@@ -329,6 +422,12 @@ export default function CertificatePage() {
)
}
// ✅ Get the final names to display
const studentName = getStudentName()
const instructorName = getInstructorName()
const courseTitle = getCourseTitle()
const completionDate = getCompletionDate()
return (
<div className="min-h-screen bg-gradient-to-br from-purple-50 to-indigo-100 py-12 px-4">
<div className="max-w-4xl mx-auto">
@@ -359,15 +458,18 @@ export default function CertificatePage() {
<p className="text-xl text-gray-600 mb-8">This is to certify that</p>
<div className="mb-8">
{/* ✅ FIXED: Using helper function for guaranteed name display */}
<div className="text-6xl font-bold text-gray-900 mb-4 border-t-4 border-b-4 border-indigo-300 py-6 capitalize font-serif">
{certificate.user_name}
{studentName}
</div>
<p className="text-sm text-gray-500">Student</p>
</div>
<p className="text-xl text-gray-600 mb-4">has successfully completed the course</p>
{/* ✅ FIXED: Using helper function for course title */}
<h3 className="text-3xl font-semibold text-gray-900 mb-8 italic font-serif">
"{certificate.course_title}"
"{courseTitle}"
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 my-8 p-6 bg-indigo-50 rounded-xl">
@@ -375,7 +477,7 @@ export default function CertificatePage() {
<Calendar className="w-8 h-8 text-indigo-600 mx-auto mb-2" />
<p className="text-sm text-gray-600">Completion Date</p>
<p className="font-semibold text-gray-900">
{new Date(certificate.completion_date).toLocaleDateString('en-US', {
{completionDate.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
@@ -394,7 +496,9 @@ export default function CertificatePage() {
<div className="text-center">
<User className="w-8 h-8 text-indigo-600 mx-auto mb-2" />
<p className="text-sm text-gray-600">Views</p>
<p className="font-semibold text-gray-900">{certificate.view_count}</p>
<p className="font-semibold text-gray-900">
{certificate.view_count || certificate.viewCount || 0}
</p>
</div>
</div>
@@ -402,8 +506,9 @@ export default function CertificatePage() {
<div className="flex justify-center">
<div className="text-center">
<div className="w-48 h-0.5 bg-gray-400 mb-3 mx-auto"></div>
{/* ✅ FIXED: Using helper function for instructor name */}
<p className="text-xl font-semibold text-gray-700">
{certificate.mentor_name}
{instructorName}
</p>
<p className="text-sm text-gray-500">Course Instructor</p>
</div>
@@ -412,13 +517,13 @@ export default function CertificatePage() {
<div className="mt-8 pt-6 border-t border-gray-200">
<p className="text-sm text-gray-500">
<strong>{certificate.issued_by}</strong><br/>
<strong>{certificate.issued_by || certificate.issuedBy || 'OpenLearnX'}</strong><br/>
Digital Certificate of Achievement<br/>
<span className="text-purple-600">🔒 Blockchain Verified</span>
</p>
{certificate.blockchain_hash && (
{(certificate.blockchain_hash || certificate.blockchainHash) && (
<p className="text-xs text-gray-400 mt-2 font-mono break-all">
Blockchain Hash: {certificate.blockchain_hash}
Blockchain Hash: {certificate.blockchain_hash || certificate.blockchainHash}
</p>
)}
</div>
@@ -447,6 +552,20 @@ export default function CertificatePage() {
<p>This certificate can be verified at any time using the certificate ID above.</p>
<p className="mt-2">Powered by OpenLearnX Secured by Blockchain Technology</p>
</div>
{/* ✅ DEBUG: Show raw certificate data in development */}
{process.env.NODE_ENV === 'development' && (
<div className="mt-8 p-4 bg-gray-100 rounded-lg">
<details>
<summary className="text-sm font-medium text-gray-700 cursor-pointer">
Debug: Raw Certificate Data
</summary>
<pre className="mt-2 text-xs text-gray-600 whitespace-pre-wrap">
{JSON.stringify(certificate, null, 2)}
</pre>
</details>
</div>
)}
</div>
</div>
)