import Modal from '@components/Objects/StyledElements/Modal/Modal'; import Image, { StaticImageData } from 'next/image'; import React, { useEffect, useState } from 'react'; import OnBoardWelcome from '@public/onboarding/OnBoardWelcome.png'; import OnBoardCourses from '@public/onboarding/OnBoardCourses.png'; import OnBoardActivities from '@public/onboarding/OnBoardActivities.png'; import OnBoardEditor from '@public/onboarding/OnBoardEditor.png'; import OnBoardAI from '@public/onboarding/OnBoardAI.png'; import OnBoardUGs from '@public/onboarding/OnBoardUGs.png'; import OnBoardAccess from '@public/onboarding/OnBoardAccess.png'; import OnBoardMore from '@public/onboarding/OnBoardMore.png'; import OnBoardAssignments from '@public/onboarding/OnBoardAssignments.png'; import OnBoardPayments from '@public/onboarding/OnBoardPayments.png'; import { ArrowRight, Book, Check, Globe, Info, PictureInPicture, Sparkle, Sprout, SquareUser, CreditCard } from 'lucide-react'; import { useRouter } from 'next/navigation'; import { getUriWithOrg } from '@services/config/config'; import { useOrg } from '@components/Contexts/OrgContext'; import useAdminStatus from '@components/Hooks/useAdminStatus'; interface OnboardingStep { imageSrc: StaticImageData; title: string; description: string; buttons?: { label: string; action: () => void; icon?: React.ReactNode; }[]; } const Onboarding: React.FC = () => { const [currentStep, setCurrentStep] = useState(() => { // Initialize with saved step or 0 const savedStep = localStorage.getItem('onboardingLastStep'); return savedStep ? parseInt(savedStep) : 0; }); const [isModalOpen, setIsModalOpen] = useState(false); const [isOnboardingComplete, setIsOnboardingComplete] = useState(true); const [isTemporarilyClosed, setIsTemporarilyClosed] = useState(false); const [isMobile, setIsMobile] = useState(false); const router = useRouter(); const org = useOrg() as any; const isUserAdmin = useAdminStatus() as any; useEffect(() => { const checkMobile = () => { setIsMobile(window.innerWidth < 768); }; // Initial check checkMobile(); // Add event listener for window resize window.addEventListener('resize', checkMobile); // Cleanup return () => window.removeEventListener('resize', checkMobile); }, []); const onboardingData: OnboardingStep[] = [ { imageSrc: OnBoardWelcome, title: 'Teach the world!', description: 'Welcome to LearnHouse, a LMS engineered for simplicity, ease of use and performance, meet the new way to create, share, and engage with educational content.', }, { imageSrc: OnBoardCourses, title: 'Create Courses', description: 'Courses are the main building blocks of LearnHouse, they always contain Chapters and Chapters contain Activities.', buttons: [ { label: 'Create New Course', action: () => router.push(getUriWithOrg(org?.slug, '/courses?new=true')), icon: , }, ], }, { imageSrc: OnBoardActivities, title: 'Activities', description: 'Activities are elements you can add to your Courses via Chapters, they can be : Dynamic Pages, Videos, Documents, Quizz and more soon.', buttons: [ { label: 'Learn more about activities', action: () => window.open('https://university.learnhouse.io/course/be89716c-9992-44bb-81df-ef3d76e355ba', '_blank'), icon: , }, ], }, { imageSrc: OnBoardEditor, title: 'Dynamic pages and The Editor', description: 'Dynamic pages are pages with dynamic content, like Notion pages they can contain various components like Quizzes, Images, Videos, Documents etc', buttons: [ { label: 'Learn more about Dynamic Pages and The Editor', action: () => window.open('https://university.learnhouse.io/course/be89716c-9992-44bb-81df-ef3d76e355ba', '_blank'), icon: , }, ], }, { imageSrc: OnBoardAI, title: 'Artificial Intelligence', description: 'Tools for tought made for teachers and students alike, context aware it can reply based on your courses and the unique content you create on LearnHouse', buttons: [ { label: 'Learn more about LearnHouse AI', action: () => window.open('https://docs.learnhouse.app/features/ai/students', '_blank'), icon: , }, ], }, { imageSrc: OnBoardUGs, title: 'Group students and streamline access ', description: 'With UserGroups you can separate students by Groups and give access to Courses depending on their needs', buttons: [ { label: 'Create UserGroups', action: () => router.push(getUriWithOrg(org?.slug, '/dash/users/settings/usergroups')), icon: , }, ], }, { imageSrc: OnBoardAccess, title: 'Choose whether to make Courses available on the Web or not ', description: 'You can choose to make your Courses discoverable from search engines and accesible to non authenticated users or to only give it to authenticated Users', buttons: [ ], }, { imageSrc: OnBoardAssignments, title: 'Create and Grade Assignments', description: 'Engage students with assignments, track their progress, and provide feedback through our intuitive grading system.', buttons: [ { label: 'Create Assignment', action: () => router.push(getUriWithOrg(org?.slug, '/dash/assignments?new=true')), icon: , }, ], }, { imageSrc: OnBoardPayments, title: 'Monetize Your Content', description: 'Set up payment plans, sell courses, and manage subscriptions with our integrated payment system.', buttons: [ { label: 'Payment Settings', action: () => router.push(getUriWithOrg(org?.slug, '/dash/payments/customers')), icon: , }, ], }, { imageSrc: OnBoardMore, title: 'To infinity and beyond', description: "To Learn more about LearnHouse, you're welcome to follow our Original courses on the LearnHouse University", buttons: [ { label: 'LearnHouse University', action: () => window.open('https://university.learnhouse.io', '_blank'), icon: , }, ], }, ]; useEffect(() => { // Check both completion and temporary closure status const isOnboardingCompleted = localStorage.getItem('isOnboardingCompleted'); const temporarilyClosed = localStorage.getItem('onboardingTemporarilyClosed'); const lastClosedTime = localStorage.getItem('onboardingLastClosedTime'); setIsOnboardingComplete(isOnboardingCompleted === 'true'); setIsTemporarilyClosed(temporarilyClosed === 'true'); // If temporarily closed, check if 24 hours have passed if (temporarilyClosed === 'true' && lastClosedTime) { const hoursSinceClosed = (Date.now() - parseInt(lastClosedTime)) / (1000 * 60 * 60); if (hoursSinceClosed >= 24) { // Reset temporary closure after 24 hours localStorage.removeItem('onboardingTemporarilyClosed'); localStorage.removeItem('onboardingLastClosedTime'); setIsTemporarilyClosed(false); } } // Show modal if onboarding is not completed and not temporarily closed setIsModalOpen(!isOnboardingCompleted && !temporarilyClosed); }, []); // Update stored step whenever currentStep changes useEffect(() => { localStorage.setItem('onboardingLastStep', currentStep.toString()); }, [currentStep]); const handleModalClose = () => { // Store temporary closure status and timestamp localStorage.setItem('onboardingTemporarilyClosed', 'true'); localStorage.setItem('onboardingLastClosedTime', Date.now().toString()); // Current step is already saved via the useEffect above setIsTemporarilyClosed(true); setIsModalOpen(false); }; const nextStep = () => { if (currentStep < onboardingData.length - 1) { setCurrentStep(currentStep + 1); } else { // Mark onboarding as completed in local storage localStorage.setItem('isOnboardingCompleted', 'true'); localStorage.removeItem('onboardingLastStep'); // Clean up stored step setIsModalOpen(false); setIsOnboardingComplete(true); console.log('Onboarding completed'); } }; const skipOnboarding = () => { localStorage.setItem('isOnboardingCompleted', 'true'); localStorage.removeItem('onboardingLastStep'); // Clean up stored step setIsModalOpen(false); setIsOnboardingComplete(true); console.log('Onboarding skipped'); }; const goToStep = (index: number) => { if (index >= 0 && index < onboardingData.length) { setCurrentStep(index); } }; return (
{isUserAdmin.isAdmin && !isUserAdmin.loading && !isOnboardingComplete && !isMobile && } dialogTrigger={

Onboarding

{ e.stopPropagation(); skipOnboarding(); }} >
} />}
); }; interface OnboardingScreenProps { step: OnboardingStep; currentStep: number; nextStep: () => void; skipOnboarding: () => void; goToStep: (index: number) => void; setIsModalOpen: (value: boolean) => void; onboardingData: OnboardingStep[]; } const OnboardingScreen: React.FC = ({ step, currentStep, nextStep, skipOnboarding, goToStep, onboardingData, setIsModalOpen, }) => { const isLastStep = currentStep === onboardingData.length - 1; return (
{onboardingData.map((_, index) => (
goToStep(index)} className={`h-[7px] w-auto ${index === currentStep ? 'bg-black' : 'bg-gray-300'} hover:bg-gray-700 rounded-lg shadow-md cursor-pointer`} >
))}

{step.title}

{step.description}

setIsModalOpen(false)} >

End

{step.buttons?.map((button, index) => (

{button.label}

{button.icon}
))} {isLastStep ? (

Finish Onboarding

) : (

Next

)}
); }; export default Onboarding;