import { ArrowUpRight, Check } from 'lucide-react'; import { Modal } from '../Modal'; import { cn } from '../../lib/classname'; import { useEffect, useMemo, useState } from 'react'; import type { AllowedOnboardingStatus } from '../../api/user'; import { pageProgressMessage } from '../../stores/page'; import { httpPatch } from '../../lib/http'; import { useToast } from '../../hooks/use-toast'; import type { OnboardingConfig } from './AccountDropdown'; import { setAuthToken } from '../../lib/jwt'; import { NUDGE_ONBOARDING_KEY } from '../OnboardingNudge.tsx'; type Task = { id: string; title: string; description: string; status: AllowedOnboardingStatus; url: string; urlText: string; onClick?: () => void; }; type OnboardingModalProps = { onClose: () => void; onboardingConfig: OnboardingConfig; onIgnoreTask?: (taskId: string, status: AllowedOnboardingStatus) => void; }; export function OnboardingModal(props: OnboardingModalProps) { const { onboardingConfig, onClose, onIgnoreTask } = props; const toast = useToast(); const [selectedTask, setSelectedTask] = useState(null); const tasks = useMemo(() => { return [ { id: 'updateProgress', title: 'Update your Progress', description: 'Mark your progress on roadmaps', status: onboardingConfig?.onboarding?.updateProgress || 'pending', url: '/roadmaps', urlText: 'Roadmaps List', }, { id: 'publishProfile', title: 'Claim a Username', description: 'Optionally create a public profile to share your skills', status: onboardingConfig?.onboarding?.publishProfile || 'pending', url: '/account/update-profile', urlText: 'Update Profile', }, { id: 'customRoadmap', title: 'Custom Roadmaps', description: 'Create your own roadmap from scratch', status: onboardingConfig?.onboarding?.customRoadmap || 'pending', url: import.meta.env.DEV ? 'http://localhost:4321' : 'https://draw.roadmap.sh', urlText: 'Create Roadmap', }, { id: 'addFriends', title: 'Invite your Friends', description: 'Invite friends to join you on roadmaps', status: onboardingConfig?.onboarding?.addFriends || 'pending', url: '/account/friends', urlText: 'Add Friends', onClick: () => { ignoreOnboardingTask( 'addFriends', 'done', 'Updating status..', ).finally(() => pageProgressMessage.set('')); }, }, { id: 'roadCard', title: 'Create your Roadmap Card', description: 'Embed your skill card on your github or website', status: onboardingConfig?.onboarding?.roadCard || 'pending', url: '/account/road-card', urlText: 'Create Road Card', onClick: () => { ignoreOnboardingTask('roadCard', 'done', 'Updating status..').finally( () => pageProgressMessage.set(''), ); }, }, { id: 'inviteTeam', title: 'Invite your Team', description: 'Invite your team to collaborate on roadmaps', status: onboardingConfig?.onboarding?.inviteTeam || 'pending', url: '/team/new', urlText: 'Create Team', }, ]; }, [onboardingConfig]); const ignoreOnboardingTask = async ( taskId: string, status: AllowedOnboardingStatus, message: string = 'Ignoring Task', ) => { pageProgressMessage.set(message); const { response, error } = await httpPatch( `${import.meta.env.PUBLIC_API_URL}/v1-update-onboarding-config`, { id: taskId, status, }, ); if (error || !response) { toast.error(error?.message || 'Failed to ignore task'); return; } onIgnoreTask?.(taskId, status); setSelectedTask(null); }; const ignoreForever = async () => { const { response, error } = await httpPatch<{ token: string }>( `${import.meta.env.PUBLIC_API_URL}/v1-ignore-onboarding-forever`, {}, ); if (error || !response) { toast.error(error?.message || 'Failed to ignore onboarding'); return; } setAuthToken(response.token); window.location.reload(); }; const isAllTasksDone = tasks.every( (task) => task.status === 'done' || task.status === 'ignored', ); useEffect(() => { if (!isAllTasksDone) { return; } pageProgressMessage.set('Finishing Onboarding'); ignoreForever().finally(() => {}); }, [isAllTasksDone]); return (

Welcome to roadmap.sh

Complete the tasks below to get started!

); }