import React, { useEffect, useState, useRef } from "react"; import axios from "axios"; import { useToast } from "@/hooks/useToast"; import { Tag } from "primereact/tag"; import Image from "next/image"; import { useRouter } from "next/router"; import ResourcePaymentButton from "@/components/bitcoinConnect/ResourcePaymentButton"; import ZapDisplay from "@/components/zaps/ZapDisplay"; import GenericButton from "@/components/buttons/GenericButton"; import { useImageProxy } from "@/hooks/useImageProxy"; import { useZapsSubscription } from "@/hooks/nostrQueries/zaps/useZapsSubscription"; import { getTotalFromZaps } from "@/utils/lightning"; import { useSession } from "next-auth/react"; import useWindowWidth from "@/hooks/useWindowWidth"; import dynamic from "next/dynamic"; import { Toast } from "primereact/toast"; import MoreOptionsMenu from "@/components/ui/MoreOptionsMenu"; import ZapThreadsWrapper from "@/components/ZapThreadsWrapper"; import appConfig from "@/config/appConfig"; import { nip19 } from "nostr-tools"; const MDDisplay = dynamic(() => import("@uiw/react-markdown-preview"), { ssr: false, }); const VideoDetails = ({ processedEvent, topics, title, summary, image, price, author, paidResource, decryptedContent, nAddress, handlePaymentSuccess, handlePaymentError, authorView, isLesson, }) => { const [zapAmount, setZapAmount] = useState(0); const [course, setCourse] = useState(null); const router = useRouter(); const { returnImageProxy } = useImageProxy(); const { zaps, zapsLoading, zapsError } = useZapsSubscription({ event: processedEvent, }); const { data: session, status } = useSession(); const { showToast } = useToast(); const windowWidth = useWindowWidth(); const isMobileView = windowWidth <= 768; const menuRef = useRef(null); const toastRef = useRef(null); const [nsec, setNsec] = useState(null); const [npub, setNpub] = useState(null); const handleDelete = async () => { try { const response = await axios.delete(`/api/resources/${processedEvent.d}`); if (response.status === 204) { showToast("success", "Success", "Resource deleted successfully."); router.push("/"); } } catch (error) { if ( error.response && error.response.data && error.response.data.error.includes("Invalid `prisma.resource.delete()`") ) { showToast( "error", "Error", "Resource cannot be deleted because it is part of a course, delete the course first." ); } else if ( error.response && error.response.data && error.response.data.error ) { showToast("error", "Error", error.response.data.error); } else { showToast( "error", "Error", "Failed to delete resource. Please try again." ); } } }; const authorMenuItems = [ { label: "Edit", icon: "pi pi-pencil", command: () => router.push(`/details/${processedEvent.id}/edit`), }, { label: "Delete", icon: "pi pi-trash", command: handleDelete, }, { label: "View Nostr note", icon: "pi pi-globe", command: () => { window.open(`https://habla.news/a/${nAddress}`, "_blank"); }, }, ]; const userMenuItems = [ { label: "View Nostr note", icon: "pi pi-globe", command: () => { window.open(`https://habla.news/a/${nAddress}`, "_blank"); }, }, ]; if (course) { userMenuItems.unshift({ label: isMobileView ? "Course" : "Open Course", icon: "pi pi-external-link", command: () => window.open(`/course/${course}`, "_blank"), }); } useEffect(() => { if (isLesson) { axios .get(`/api/resources/${processedEvent.d}`) .then((res) => { if (res.data && res.data.lessons[0]?.courseId) { setCourse(res.data.lessons[0]?.courseId); } }) .catch((err) => { console.error("err", err); }); } }, [processedEvent.d, isLesson]); useEffect(() => { if (zaps.length > 0) { const total = getTotalFromZaps(zaps, processedEvent); setZapAmount(total); } }, [zaps, processedEvent]); useEffect(() => { if (session?.user?.privkey) { const privkeyBuffer = Buffer.from(session.user.privkey, "hex"); setNsec(nip19.nsecEncode(privkeyBuffer)); } else if (session?.user?.pubkey) { setNpub(nip19.npubEncode(session.user.pubkey)); } }, [session]); const renderPaymentMessage = () => { if (session?.user && session.user?.role?.subscribed && decryptedContent) { return ( ); } // if the user paid for the course that this lesson is in, show a message that says you have this lesson through the course and show how much you paid for the course if ( isLesson && course && session?.user?.purchased?.some((purchase) => purchase.courseId === course) ) { return ( purchase.courseId === course )?.course?.price } sats for the course.`} icon="pi pi-check" label={`Paid ${ session?.user?.purchased?.find( (purchase) => purchase.courseId === course )?.course?.price } sats`} severity="success" outlined size="small" className="cursor-default hover:opacity-100 hover:bg-transparent focus:ring-0" /> ); } if ( paidResource && decryptedContent && author && processedEvent?.pubkey !== session?.user?.pubkey && !session?.user?.role?.subscribed ) { return ( ); } if ( paidResource && author && processedEvent?.pubkey === session?.user?.pubkey ) { return ( ); } return null; }; const renderContent = () => { if (decryptedContent) { return ( ); } if (paidResource && !decryptedContent) { return ( This content is paid and needs to be purchased before viewing. ); } if (processedEvent?.content) { return ( ); } return null; }; return ( {renderContent()} {title} {topics && topics.length > 0 && topics.map((topic, index) => ( ))} {isLesson && } {summary?.split("\n").map((line, index) => ( {line} ))} By{" "} {author?.username} {renderPaymentMessage()} {nAddress && ( {!paidResource || decryptedContent || session?.user?.role?.subscribed ? ( ) : ( Comments are only available to content purchasers, subscribers, and the content creator. )} )} ); }; export default VideoDetails;
This content is paid and needs to be purchased before viewing.
{line}
By{" "} {author?.username}
Comments are only available to content purchasers, subscribers, and the content creator.