import { FormField, FormLabelAndMessage, Input, Textarea, } from '@components/Objects/StyledElements/Form/Form'; import { useFormik } from 'formik'; import { AlertTriangle, Award, FileText, Settings } from 'lucide-react'; import CertificatePreview from './CertificatePreview'; import * as Form from '@radix-ui/react-form'; import React, { useEffect, useState } from 'react'; import { useCourse, useCourseDispatch } from '@components/Contexts/CourseContext'; import { useLHSession } from '@components/Contexts/LHSessionContext'; import { createCertification, updateCertification, deleteCertification } from '@services/courses/certifications'; import { CustomSelect, CustomSelectContent, CustomSelectItem, CustomSelectTrigger, CustomSelectValue, } from "../EditCourseGeneral/CustomSelect"; import useSWR, { mutate } from 'swr'; import { getAPIUrl } from '@services/config/config'; import toast from 'react-hot-toast'; type EditCourseCertificationProps = { orgslug: string course_uuid?: string } const validate = (values: any) => { const errors = {} as any; if (values.enable_certification && !values.certification_name) { errors.certification_name = 'Required when certification is enabled'; } else if (values.certification_name && values.certification_name.length > 100) { errors.certification_name = 'Must be 100 characters or less'; } if (values.enable_certification && !values.certification_description) { errors.certification_description = 'Required when certification is enabled'; } else if (values.certification_description && values.certification_description.length > 500) { errors.certification_description = 'Must be 500 characters or less'; } return errors; }; function EditCourseCertification(props: EditCourseCertificationProps) { const [error, setError] = useState(''); const [isCreating, setIsCreating] = useState(false); const course = useCourse(); const dispatchCourse = useCourseDispatch() as any; const { isLoading, courseStructure } = course as any; const session = useLHSession() as any; const access_token = session?.data?.tokens?.access_token; // Fetch existing certifications const { data: certifications, error: certificationsError, mutate: mutateCertifications } = useSWR( courseStructure?.course_uuid && access_token ? `certifications/course/${courseStructure.course_uuid}` : null, async () => { if (!courseStructure?.course_uuid || !access_token) return null; const result = await fetch( `${getAPIUrl()}certifications/course/${courseStructure.course_uuid}`, { method: 'GET', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${access_token}`, }, credentials: 'include', } ); const response = await result.json(); if (result.status === 200) { return { success: true, data: response, status: result.status, HTTPmessage: result.statusText, }; } else { return { success: false, data: response, status: result.status, HTTPmessage: result.statusText, }; } } ); const existingCertification = certifications?.data?.[0]; // Assuming one certification per course const hasExistingCertification = !!existingCertification; // Create initial values object const getInitialValues = () => { // Helper function to get instructor name from authors const getInstructorName = () => { if (courseStructure?.authors && courseStructure.authors.length > 0) { const author = courseStructure.authors[0]; const firstName = author.first_name || ''; const lastName = author.last_name || ''; // Only return if at least one name exists if (firstName || lastName) { return `${firstName} ${lastName}`.trim(); } } return ''; }; // Use existing certification data if available, otherwise fall back to course data const config = existingCertification?.config || {}; return { enable_certification: hasExistingCertification, certification_name: config.certification_name || courseStructure?.name || '', certification_description: config.certification_description || courseStructure?.description || '', certification_type: config.certification_type || 'completion', certificate_pattern: config.certificate_pattern || 'professional', certificate_instructor: config.certificate_instructor || getInstructorName(), }; }; const formik = useFormik({ initialValues: getInitialValues(), validate, onSubmit: async values => { // This is no longer used - saving is handled by the main Save button }, enableReinitialize: true, }) as any; // Handle enabling/disabling certification const handleCertificationToggle = async (enabled: boolean) => { if (enabled && !hasExistingCertification) { // Create new certification setIsCreating(true); try { const config = { certification_name: formik.values.certification_name || courseStructure?.name || '', certification_description: formik.values.certification_description || courseStructure?.description || '', certification_type: formik.values.certification_type || 'completion', certificate_pattern: formik.values.certificate_pattern || 'professional', certificate_instructor: formik.values.certificate_instructor || '', }; const result = await createCertification( courseStructure.id, config, access_token ); // createCertification uses errorHandling which returns JSON directly on success if (result) { toast.success('Certification created successfully'); mutateCertifications(); formik.setFieldValue('enable_certification', true); } else { throw new Error('Failed to create certification'); } } catch (e) { setError('Failed to create certification.'); toast.error('Failed to create certification'); formik.setFieldValue('enable_certification', false); } finally { setIsCreating(false); } } else if (!enabled && hasExistingCertification) { // Delete existing certification try { const result = await deleteCertification( existingCertification.certification_uuid, access_token ); // deleteCertification uses errorHandling which returns JSON directly on success if (result) { toast.success('Certification removed successfully'); mutateCertifications(); formik.setFieldValue('enable_certification', false); } else { throw new Error('Failed to delete certification'); } } catch (e) { setError('Failed to remove certification.'); toast.error('Failed to remove certification'); formik.setFieldValue('enable_certification', true); } } else { formik.setFieldValue('enable_certification', enabled); } }; // Reset form when certifications data changes useEffect(() => { if (certifications && !isLoading) { const newValues = getInitialValues(); formik.resetForm({ values: newValues }); } }, [certifications, isLoading]); // Handle form changes - update course context with certification data useEffect(() => { if (!isLoading && hasExistingCertification) { const formikValues = formik.values as any; const initialValues = formik.initialValues as any; const valuesChanged = Object.keys(formikValues).some( key => formikValues[key] !== initialValues[key] ); if (valuesChanged) { dispatchCourse({ type: 'setIsNotSaved' }); // Store certification data in course context so it gets saved with the main save button const updatedCourse = { ...courseStructure, // Store certification data for the main save functionality _certificationData: { certification_uuid: existingCertification.certification_uuid, config: { certification_name: formikValues.certification_name, certification_description: formikValues.certification_description, certification_type: formikValues.certification_type, certificate_pattern: formikValues.certificate_pattern, certificate_instructor: formikValues.certificate_instructor, } } }; dispatchCourse({ type: 'setCourseStructure', payload: updatedCourse }); } } }, [formik.values, isLoading, hasExistingCertification, existingCertification]); if (isLoading || !courseStructure || (courseStructure.course_uuid && access_token && certifications === undefined)) { return
Loading...
; } if (certificationsError) { return
Error loading certifications
; } return (
{courseStructure && (
{/* Header Section */}

Course Certification

Enable and configure certificates for students who complete this course

{isCreating && (
)}
{error && (
{error}
)} {/* Certification Configuration - Only show if enabled and has existing certification */} {formik.values.enable_certification && hasExistingCertification && (
{/* Form Section */}
{/* Basic Information Section */}

Basic Information

Configure the basic details of your certification

{/* Certification Name */} {/* Certification Type */} { if (!value) return; formik.setFieldValue('certification_type', value); }} > {formik.values.certification_type === 'completion' ? 'Course Completion' : formik.values.certification_type === 'achievement' ? 'Achievement Based' : formik.values.certification_type === 'assessment' ? 'Assessment Based' : formik.values.certification_type === 'participation' ? 'Participation' : formik.values.certification_type === 'mastery' ? 'Skill Mastery' : formik.values.certification_type === 'professional' ? 'Professional Development' : formik.values.certification_type === 'continuing' ? 'Continuing Education' : formik.values.certification_type === 'workshop' ? 'Workshop Attendance' : formik.values.certification_type === 'specialization' ? 'Specialization' : 'Course Completion'} Course Completion Achievement Based Assessment Based Participation Skill Mastery Professional Development Continuing Education Workshop Attendance Specialization
{/* Certification Description */}