import React, { useEffect, useState } from 'react'; import axios from 'axios'; import { useRouter } from 'next/router'; import { useNostr } from '@/hooks/useNostr'; import { parseEvent, findKind0Fields, hexToNpub } from '@/utils/nostr'; import { verifyEvent, nip19, nip04 } from 'nostr-tools'; import { v4 as uuidv4 } from 'uuid'; import { useLocalStorageWithEffect } from '@/hooks/useLocalStorage'; import { useImageProxy } from '@/hooks/useImageProxy'; import { Button } from 'primereact/button'; import { useToast } from '@/hooks/useToast'; import { Tag } from 'primereact/tag'; import Image from 'next/image'; import useResponsiveImageDimensions from '@/hooks/useResponsiveImageDimensions'; import 'primeicons/primeicons.css'; import ReactMarkdown from 'react-markdown'; import rehypeRaw from 'rehype-raw'; const MarkdownContent = ({ content }) => { // Function to strip HTML tags const stripHtml = (html) => { let tmp = document.createElement("DIV"); tmp.innerHTML = html; return tmp.textContent || tmp.innerText || ""; }; // Strip HTML tags from the content const plainContent = stripHtml(content); return (
{plainContent}
); }; export default function Details() { const [draft, setDraft] = useState(null); const { returnImageProxy } = useImageProxy(); const { publishCourse, publishResource, fetchSingleEvent } = useNostr(); const [user] = useLocalStorageWithEffect('user', {}); const { width, height } = useResponsiveImageDimensions(); const router = useRouter(); const { showToast } = useToast(); useEffect(() => { if (router.isReady) { const { slug } = router.query; axios.get(`/api/drafts/${slug}`) .then(res => { console.log('res:', res.data); setDraft(res.data); }) .catch(err => { console.error(err); }); } }, [router.isReady, router.query]); const handleSubmit = async () => { if (draft) { const { unsignedEvent, type } = await buildEvent(draft); if (unsignedEvent) { const published = await publishEvent(unsignedEvent, type); // if successful, delete the draft, redirect to profile if (published) { axios.delete(`/api/drafts/${draft.id}`) .then(res => { if (res.status === 204) { showToast('success', 'Success', 'Draft deleted successfully.'); router.push(`/profile`); } else { showToast('error', 'Error', 'Failed to delete draft.'); } }) .catch(err => { console.error(err); }); } } else { showToast('error', 'Error', 'Failed to broadcast resource. Please try again.'); } } } const handleDelete = async () => { if (draft) { await axios.delete(`/api/drafts/${draft.id}`) .then(res => { if (res.status === 204) { showToast('success', 'Success', 'Draft deleted successfully.'); router.push(`/profile`); } else { showToast('error', 'Error', 'Failed to delete draft.'); } }) .catch(err => { console.error(err); }); } } const publishEvent = async (event, type) => { const dTag = event.tags.find(tag => tag[0] === 'd')[1]; const signedEvent = await window.nostr.signEvent(event); const eventVerification = await verifyEvent(signedEvent); if (!eventVerification) { showToast('error', 'Error', 'Event verification failed. Please try again.'); return; } const nAddress = nip19.naddrEncode({ pubkey: signedEvent.pubkey, kind: signedEvent.kind, identifier: dTag, }) console.log('nAddress:', nAddress); const userResponse = await axios.get(`/api/users/${user.pubkey}`) if (!userResponse.data) { showToast('error', 'Error', 'User not found', 'Please try again.'); return; } const payload = { id: dTag, userId: userResponse.data.id, price: draft.price || 0, noteId: nAddress, } const response = await axios.post(`/api/resources`, payload); if (response.status !== 201) { showToast('error', 'Error', 'Failed to create resource. Please try again.'); return; } let published; if (type === 'resource' || type === 'workshop') { published = await publishResource(signedEvent); } else if (type === 'course') { published = await publishCourse(signedEvent); } console.log('published:', published); if (published) { // check if the event is published const publishedEvent = await fetchSingleEvent(signedEvent.id); console.log('publishedEvent:', publishedEvent); if (publishedEvent) { // show success message showToast('success', 'Success', `${type} published successfully.`); // delete the draft console.log('draft:', draft); await axios.delete(`/api/drafts/${draft.id}`) .then(res => { if (res.status === 204) { showToast('success', 'Success', 'Draft deleted successfully.'); router.push(`/profile`); } else { showToast('error', 'Error', 'Failed to delete draft.'); } }) .catch(err => { console.error(err); }); } } } const buildEvent = async (draft) => { const NewDTag = uuidv4(); let event = {}; let type; let encryptedContent; switch (draft?.type) { case 'resource': if (draft?.price) { // encrypt the content with NEXT_PUBLIC_APP_PRIV_KEY to NEXT_PUBLIC_APP_PUBLIC_KEY encryptedContent = await nip04.encrypt(process.env.NEXT_PUBLIC_APP_PRIV_KEY, process.env.NEXT_PUBLIC_APP_PUBLIC_KEY, draft.content); } event = { kind: draft?.price ? 30402 : 30023, // Determine kind based on if price is present content: draft?.price ? encryptedContent : draft.content, created_at: Math.floor(Date.now() / 1000), tags: [ ['d', NewDTag], ['title', draft.title], ['summary', draft.summary], ['image', draft.image], ...draft.topics.map(topic => ['t', topic]), ['published_at', Math.floor(Date.now() / 1000).toString()], // Include price and location tags only if price is present ...(draft?.price ? [['price', draft.price], ['location', `https://plebdevs.com/resource/${draft.id}`]] : []), ] }; type = 'resource'; break; case 'workshop': if (draft?.price) { // encrypt the content with NEXT_PUBLIC_APP_PRIV_KEY to NEXT_PUBLIC_APP_PUBLIC_KEY encryptedContent = await nip04.encrypt(process.env.NEXT_PUBLIC_APP_PRIV_KEY, process.env.NEXT_PUBLIC_APP_PUBLIC_KEY, draft.content); } event = { kind: draft?.price ? 30402 : 30023, content: draft?.price ? encryptedContent : draft.content, created_at: Math.floor(Date.now() / 1000), tags: [ ['d', NewDTag], ['title', draft.title], ['summary', draft.summary], ['image', draft.image], ...draft.topics.map(topic => ['t', topic]), ['published_at', Math.floor(Date.now() / 1000).toString()], ] }; type = 'workshop'; break; case 'course': event = { kind: 30023, content: draft.content, created_at: Math.floor(Date.now() / 1000), tags: [ ['d', NewDTag], ['title', draft.title], ['summary', draft.summary], ['image', draft.image], ...draft.topics.map(topic => ['t', topic]), ['published_at', Math.floor(Date.now() / 1000).toString()], ] }; type = 'course'; break; default: event = null; type = 'unknown'; } return { unsignedEvent: event, type }; }; return (
{/* router.push('/')} /> */}
{/* List out topics */} {draft?.topics && draft.topics.map((topic, index) => { if (topic === "plebdevs") return; return ( ) }) }

{draft?.title}

{draft?.summary}

resource thumbnail {user && user?.pubkey && (

Created by{' '} {user?.username || user?.pubkey.slice(0, 10)}{'... '}

)}
{draft && (
router.push(`/details/${draft.id}`)} className="flex flex-col items-center mx-auto cursor-pointer rounded-md shadow-lg">
resource thumbnail
)}
{ draft?.content && }
); }