Merge pull request #409 from learnhouse/feat/onboarding-updates

Improve onboarding UX
This commit is contained in:
Badr B. 2024-12-01 20:11:55 +01:00 committed by GitHub
commit 87787724c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 80 additions and 11 deletions

View file

@ -9,7 +9,9 @@ import OnBoardAI from '@public/onboarding/OnBoardAI.png';
import OnBoardUGs from '@public/onboarding/OnBoardUGs.png'; import OnBoardUGs from '@public/onboarding/OnBoardUGs.png';
import OnBoardAccess from '@public/onboarding/OnBoardAccess.png'; import OnBoardAccess from '@public/onboarding/OnBoardAccess.png';
import OnBoardMore from '@public/onboarding/OnBoardMore.png'; import OnBoardMore from '@public/onboarding/OnBoardMore.png';
import { ArrowRight, Book, Check, Globe, Info, PictureInPicture, Sparkle, Sprout, SquareUser } from 'lucide-react'; 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 { useRouter } from 'next/navigation';
import { getUriWithOrg } from '@services/config/config'; import { getUriWithOrg } from '@services/config/config';
import { useOrg } from '@components/Contexts/OrgContext'; import { useOrg } from '@components/Contexts/OrgContext';
@ -27,9 +29,14 @@ interface OnboardingStep {
} }
const Onboarding: React.FC = () => { const Onboarding: React.FC = () => {
const [currentStep, setCurrentStep] = useState(0); 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 [isModalOpen, setIsModalOpen] = useState(false);
const [isOnboardingComplete, setIsOnboardingComplete] = useState(true); const [isOnboardingComplete, setIsOnboardingComplete] = useState(true);
const [isTemporarilyClosed, setIsTemporarilyClosed] = useState(false);
const router = useRouter(); const router = useRouter();
const org = useOrg() as any; const org = useOrg() as any;
const isUserAdmin = useAdminStatus() as any; const isUserAdmin = useAdminStatus() as any;
@ -108,6 +115,30 @@ const Onboarding: React.FC = () => {
], ],
}, },
{
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: <Book size={16} />,
},
],
},
{
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: <CreditCard size={16} />,
},
],
},
{ {
imageSrc: OnBoardMore, imageSrc: OnBoardMore,
title: 'To infinity and beyond', title: 'To infinity and beyond',
@ -123,28 +154,60 @@ const Onboarding: React.FC = () => {
]; ];
useEffect(() => { useEffect(() => {
// Check if onboarding is already completed in local storage // Check both completion and temporary closure status
const isOnboardingCompleted = localStorage.getItem('isOnboardingCompleted'); const isOnboardingCompleted = localStorage.getItem('isOnboardingCompleted');
const temporarilyClosed = localStorage.getItem('onboardingTemporarilyClosed');
const lastClosedTime = localStorage.getItem('onboardingLastClosedTime');
setIsOnboardingComplete(isOnboardingCompleted === 'true'); setIsOnboardingComplete(isOnboardingCompleted === 'true');
setIsModalOpen(!isOnboardingCompleted); // Show modal if onboarding is not completed 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 = () => { const nextStep = () => {
if (currentStep < onboardingData.length - 1) { if (currentStep < onboardingData.length - 1) {
setCurrentStep(currentStep + 1); setCurrentStep(currentStep + 1);
} else { } else {
// Mark onboarding as completed in local storage // Mark onboarding as completed in local storage
localStorage.setItem('isOnboardingCompleted', 'true'); localStorage.setItem('isOnboardingCompleted', 'true');
setIsModalOpen(false); // Close modal after completion localStorage.removeItem('onboardingLastStep'); // Clean up stored step
setIsOnboardingComplete(true); // Show success message setIsModalOpen(false);
setIsOnboardingComplete(true);
console.log('Onboarding completed'); console.log('Onboarding completed');
} }
}; };
const skipOnboarding = () => { const skipOnboarding = () => {
// Mark onboarding as completed in local storage
localStorage.setItem('isOnboardingCompleted', 'true'); localStorage.setItem('isOnboardingCompleted', 'true');
setIsModalOpen(false); // Close modal after skipping localStorage.removeItem('onboardingLastStep'); // Clean up stored step
setIsModalOpen(false);
console.log('Onboarding skipped'); console.log('Onboarding skipped');
}; };
@ -168,8 +231,7 @@ const Onboarding: React.FC = () => {
currentStep={currentStep} currentStep={currentStep}
nextStep={nextStep} nextStep={nextStep}
skipOnboarding={skipOnboarding} skipOnboarding={skipOnboarding}
setIsModalOpen={setIsModalOpen} setIsModalOpen={handleModalClose}
goToStep={goToStep} goToStep={goToStep}
/> />
} }
@ -213,7 +275,14 @@ const OnboardingScreen: React.FC<OnboardingScreenProps> = ({
<div className='flex flex-col'> <div className='flex flex-col'>
<div className='onboarding_screens flex-col px-4 py-4'> <div className='onboarding_screens flex-col px-4 py-4'>
<div className='flex-grow rounded-xl'> <div className='flex-grow rounded-xl'>
<Image unoptimized className='mx-auto shadow-md shadow-gray-200 rounded-lg aspect-auto' alt='' priority quality={100} src={step.imageSrc} /> <Image
unoptimized
className='mx-auto shadow-md shadow-gray-200 rounded-lg w-[730px] h-[330px] object-cover'
alt=''
priority
quality={100}
src={step.imageSrc}
/>
</div> </div>
<div className='grid grid-flow-col justify-stretch space-x-3 mt-4'> <div className='grid grid-flow-col justify-stretch space-x-3 mt-4'>
{onboardingData.map((_, index) => ( {onboardingData.map((_, index) => (

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 KiB