useCourseData into reusable hooks

This commit is contained in:
austinkelsay 2025-05-11 12:58:37 -05:00
parent 045418397c
commit 51cd1e4d97
No known key found for this signature in database
GPG Key ID: 5A763922E5BA08EE
3 changed files with 145 additions and 1 deletions

View File

@ -1,9 +1,13 @@
import useCourseDecryption from '../encryption/useCourseDecryption';
import useCourseTabs from './useCourseTabs';
import useCoursePayment from './useCoursePayment';
import useCourseData from './useCourseData';
import useLessons from './useLessons';
export {
useCourseDecryption,
useCourseTabs,
useCoursePayment
useCoursePayment,
useCourseData,
useLessons
};

View File

@ -0,0 +1,79 @@
import { useEffect, useState } from 'react';
import { parseCourseEvent } from '@/utils/nostr';
import { nip19 } from 'nostr-tools';
import { useToast } from '../useToast';
/**
* Hook to fetch and manage course data
* @param {Object} ndk - NDK instance for Nostr data fetching
* @param {Function} fetchAuthor - Function to fetch author data
* @param {Object} router - Next.js router instance
* @returns {Object} Course data and related state
*/
const useCourseData = (ndk, fetchAuthor, router) => {
const [course, setCourse] = useState(null);
const [lessonIds, setLessonIds] = useState([]);
const [paidCourse, setPaidCourse] = useState(null);
const [loading, setLoading] = useState(true);
const { showToast } = useToast();
useEffect(() => {
if (!router.isReady) return;
const { slug } = router.query;
const fetchCourseId = async () => {
if (slug.includes('naddr')) {
const { data } = nip19.decode(slug);
if (!data?.identifier) {
showToast('error', 'Error', 'Resource not found');
return null;
}
return data.identifier;
} else {
return slug;
}
};
const fetchCourse = async courseId => {
try {
await ndk.connect();
const event = await ndk.fetchEvent({ '#d': [courseId] });
if (!event) return null;
const author = await fetchAuthor(event.pubkey);
const lessonIds = event.tags.filter(tag => tag[0] === 'a').map(tag => tag[1].split(':')[2]);
const parsedCourse = { ...parseCourseEvent(event), author };
return { parsedCourse, lessonIds };
} catch (error) {
console.error('Error fetching event:', error);
return null;
}
};
const initializeCourse = async () => {
setLoading(true);
const id = await fetchCourseId();
if (!id) {
setLoading(false);
return;
}
const courseData = await fetchCourse(id);
if (courseData) {
const { parsedCourse, lessonIds } = courseData;
setCourse(parsedCourse);
setLessonIds(lessonIds);
setPaidCourse(parsedCourse.price && parsedCourse.price > 0);
}
setLoading(false);
};
initializeCourse();
}, [router.isReady, router.query, ndk, fetchAuthor, showToast]);
return { course, lessonIds, paidCourse, loading };
};
export default useCourseData;

View File

@ -0,0 +1,61 @@
import { useState, useEffect } from 'react';
import { parseEvent } from '@/utils/nostr';
/**
* Hook to fetch and manage lesson data for a course
* @param {Object} ndk - NDK instance for Nostr data fetching
* @param {Function} fetchAuthor - Function to fetch author data
* @param {Array} lessonIds - Array of lesson IDs to fetch
* @param {String} pubkey - Public key of the course author
* @returns {Object} Lesson data and state
*/
const useLessons = (ndk, fetchAuthor, lessonIds, pubkey) => {
const [lessons, setLessons] = useState([]);
const [uniqueLessons, setUniqueLessons] = useState([]);
// Fetch lessons when IDs or pubkey change
useEffect(() => {
if (lessonIds.length > 0 && pubkey) {
const fetchLessons = async () => {
try {
await ndk.connect();
// Create a single filter with all lesson IDs to avoid multiple calls
const filter = {
'#d': lessonIds,
kinds: [30023, 30402],
authors: [pubkey],
};
const events = await ndk.fetchEvents(filter);
const newLessons = [];
// Process events
for (const event of events) {
const author = await fetchAuthor(event.pubkey);
const parsedLesson = { ...parseEvent(event), author };
newLessons.push(parsedLesson);
}
setLessons(newLessons);
} catch (error) {
console.error('Error fetching events:', error);
}
};
fetchLessons();
}
}, [lessonIds, ndk, fetchAuthor, pubkey]);
// Deduplicate lessons
useEffect(() => {
const newUniqueLessons = Array.from(
new Map(lessons.map(lesson => [lesson.id, lesson])).values()
);
setUniqueLessons(newUniqueLessons);
}, [lessons]);
return { lessons, uniqueLessons, setLessons };
};
export default useLessons;