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 router = useRouter();
const org = useOrg() as any;
const isUserAdmin = useAdminStatus() as any;
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);
console.log('Onboarding skipped');
};
const goToStep = (index: number) => {
if (index >= 0 && index < onboardingData.length) {
setCurrentStep(index);
}
};
return (
{isUserAdmin.isAdmin && !isUserAdmin.loading && !isOnboardingComplete &&
}
dialogTrigger={
}
/>}
);
};
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}
{step.buttons?.map((button, index) => (
{button.label}
{button.icon}
))}
{isLastStep ? (
) : (
)}
);
};
export default Onboarding;