@ Marth
2024-08-18 23:02:09
```js
import React, { useEffect, useState, useCallback, useRef } from 'react';
import { useRouter } from 'next/router';
import { useImageProxy } from '@/hooks/useImageProxy';
import { Tag } from 'primereact/tag';
import { Button } from 'primereact/button';
import Image from 'next/image';
import dynamic from 'next/dynamic';
import axios from 'axios';
import { nip04, nip19 } from 'nostr-tools';
import { v4 as uuidv4 } from 'uuid';
import { useSession } from 'next-auth/react';
import { useNDKContext } from "@/context/NDKContext";
import { NDKEvent } from "@nostr-dev-kit/ndk";
import { findKind0Fields } from '@/utils/nostr';
import { useToast } from '@/hooks/useToast';
import 'primeicons/primeicons.css';
const MDDisplay = dynamic(() => import("@uiw/react-markdown-preview"), { ssr: false });
// ... keep the validateEvent function as is ...
export default function DraftCourseDetails({ processedEvent, draftId, lessons }) {
// ... keep state declarations and hooks as is ...
const fetchAuthor = useCallback(async (pubkey) => {
if (!pubkey) return;
const author = await ndk.getUser({ pubkey });
const profile = await author.fetchProfile();
const fields = await findKind0Fields(profile);
if (fields) setAuthor(fields);
}, [ndk]);
useEffect(() => {
if (processedEvent) fetchAuthor(processedEvent?.user?.pubkey);
}, [fetchAuthor, processedEvent]);
useEffect(() => {
if (session) setUser(session.user);
}, [session]);
const handleDelete = async () => {
try {
await axios.delete(`/api/courses/drafts/${processedEvent.id}`);
showToast('success', 'Success', 'Draft Course deleted successfully');
router.push('/');
} catch (error) {
showToast('error', 'Error', 'Failed to delete draft course');
}
};
const handlePostResource = async (resource) => {
// ... keep this function as is ...
};
const createCourseEvent = (courseId, title, summary, coverImage, lessons, price) => {
const event = new NDKEvent(ndk);
event.kind = 30004;
event.content = "";
event.tags = [
['d', courseId],
['name', title],
['picture', coverImage],
['image', coverImage],
['description', summary],
['l', "Education"],
['price', price.toString()],
...lessons.map((lesson) => ['a', `${lesson.kind}:${lesson.pubkey}:${lesson.d}`]),
];
return event;
};
const handleSubmit = async (e) => {
e.preventDefault();
const newCourseId = uuidv4();
try {
if (!ndk.signer) await addSigner();
// Process lessons
await Promise.all(processedLessons.map(async (lesson) => {
const unpublished = lesson?.unpublished;
if (unpublished && Object.keys(unpublished).length > 0) {
const validationResult = validateEvent(unpublished);
if (validationResult !== true) {
throw new Error(`Invalid event: ${validationResult}`);
}
const published = await unpublished.publish();
const saved = await handlePostResource(unpublished);
if (published && saved) {
await axios.delete(`/api/drafts/${lesson?.d}`);
}
}
}));
// Create and publish course
const courseEvent = createCourseEvent(newCourseId, processedEvent.title, processedEvent.summary, processedEvent.image, processedLessons, processedEvent.price);
const published = await courseEvent.publish();
if (!published) {
throw new Error('Failed to publish course');
}
// Save course to db
await axios.post('/api/courses', {
id: newCourseId,
resources: {
connect: processedLessons.map(lesson => ({ id: lesson?.d }))
},
noteId: courseEvent.id,
user: {
connect: { id: user.id }
},
price: processedEvent?.price || 0
});
// Update resources with course id
await Promise.all(processedLessons.map(lesson =>
axios.put(`/api/resources/${lesson?.d}`, { courseId: newCourseId })
));
// Delete draft
await axios.delete(`/api/courses/drafts/${processedEvent.id}`);
showToast('success', 'Success', 'Course created successfully');
router.push(`/course/${courseEvent.id}`);
} catch (error) {
console.error('Error creating course:', error);
showToast('error', 'Error', error.message || 'Failed to create course. Please try again.');
}
};
useEffect(() => {
const buildEvent = async (draft) => {
// ... keep this function as is ...
};
const buildDraftEvent = async (lesson) => {
const { unsignedEvent } = await buildEvent(lesson);
return unsignedEvent;
};
const processLessons = async () => {
if (!hasRunEffect.current && lessons.length > 0 && user && author) {
hasRunEffect.current = true;
const processedLessons = await Promise.all(lessons.map(async (lesson) => {
const isDraft = !lesson?.pubkey;
if (isDraft) {
const unsignedEvent = await buildDraftEvent(lesson);
return {
d: lesson?.id,
kind: lesson?.price ? 30402 : 30023,
pubkey: unsignedEvent.pubkey,
unpublished: unsignedEvent
};
} else {
return {
d: lesson?.d,
kind: lesson?.price ? 30402 : 30023,
pubkey: lesson.pubkey
};
}
}));
setProcessedLessons(processedLessons);
}
};
processLessons();
}, [lessons, user, author, ndk]);
// ... keep the return statement (JSX) as is ...
}
```