Add routeable lesson URLs for bootcamp pages

Implement deep linking to individual lessons with URL pattern:
- Route: /bootcamp/{product-slug}/{lessonId}
- lessonId parameter is optional for backward compatibility
- When no lessonId provided, defaults to first lesson
- Clicking lessons updates URL without page reload
- URL parameter drives lesson selection on page load

Changes:
- Update App.tsx route to accept optional :lessonId parameter
- Add lessonId extraction in Bootcamp.tsx useParams
- Implement handleSelectLesson to update URL on lesson click
- Update lesson selection logic to read from URL parameter
- Fallback to first lesson if lessonId not found

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dwindown
2025-12-31 12:47:42 +07:00
parent a9ad84eb23
commit 9e76d07cc2
2 changed files with 23 additions and 4 deletions

View File

@@ -55,7 +55,7 @@ interface UserReview {
}
export default function Bootcamp() {
const { slug } = useParams<{ slug: string }>();
const { slug, lessonId } = useParams<{ slug: string; lessonId?: string }>();
const navigate = useNavigate();
const { user, loading: authLoading } = useAuth();
@@ -134,7 +134,20 @@ export default function Bootcamp() {
}));
setModules(sortedModules);
if (sortedModules.length > 0 && sortedModules[0].lessons.length > 0) {
// Select lesson based on URL parameter or default to first lesson
const allLessons = sortedModules.flatMap(m => m.lessons);
if (lessonId) {
// Find the lesson by ID from URL
const lessonFromUrl = allLessons.find(l => l.id === lessonId);
if (lessonFromUrl) {
setSelectedLesson(lessonFromUrl);
} else if (allLessons.length > 0) {
// If lesson not found, default to first lesson
setSelectedLesson(allLessons[0]);
}
} else if (allLessons.length > 0 && sortedModules[0].lessons.length > 0) {
// No lessonId in URL, select first lesson
setSelectedLesson(sortedModules[0].lessons[0]);
}
}
@@ -170,6 +183,12 @@ export default function Bootcamp() {
return progress.some(p => p.lesson_id === lessonId);
};
const handleSelectLesson = (lesson: Lesson) => {
setSelectedLesson(lesson);
// Update URL without full page reload
navigate(`/bootcamp/${slug}/${lesson.id}`);
};
const markAsCompleted = async () => {
if (!selectedLesson || !user || !product) return;
@@ -347,7 +366,7 @@ export default function Bootcamp() {
key={lesson.id}
onClick={() => {
if (isReleased) {
setSelectedLesson(lesson);
handleSelectLesson(lesson);
setMobileMenuOpen(false);
}
}}