mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-06 18:31:00 +00:00
Segregate paid resources with paid courses and vice versa, fix paid field on workshop
This commit is contained in:
parent
cee1679a8b
commit
374bef5a51
@ -31,7 +31,9 @@ export default function WorkshopsCarousel() {
|
|||||||
const fetch = async () => {
|
const fetch = async () => {
|
||||||
try {
|
try {
|
||||||
if (workshops && workshops.length > 0) {
|
if (workshops && workshops.length > 0) {
|
||||||
|
console.log('workshops', workshops);
|
||||||
const processedWorkshops = workshops.map(workshop => parseEvent(workshop));
|
const processedWorkshops = workshops.map(workshop => parseEvent(workshop));
|
||||||
|
console.log('processedWorkshops', processedWorkshops);
|
||||||
setProcessedWorkshops(processedWorkshops);
|
setProcessedWorkshops(processedWorkshops);
|
||||||
} else {
|
} else {
|
||||||
console.log('No workshops fetched or empty array returned');
|
console.log('No workshops fetched or empty array returned');
|
||||||
|
@ -13,7 +13,8 @@ import { useNDKContext } from "@/context/NDKContext";
|
|||||||
import { useZapsSubscription } from '@/hooks/nostrQueries/zaps/useZapsSubscription';
|
import { useZapsSubscription } from '@/hooks/nostrQueries/zaps/useZapsSubscription';
|
||||||
import { findKind0Fields } from '@/utils/nostr';
|
import { findKind0Fields } from '@/utils/nostr';
|
||||||
import 'primeicons/primeicons.css';
|
import 'primeicons/primeicons.css';
|
||||||
import ResourcePaymentButton from "@/components/bitcoinConnect/ResourcePaymentButton";
|
import CoursePaymentButton from "@/components/bitcoinConnect/CoursePaymentButton";
|
||||||
|
import { ProgressSpinner } from 'primereact/progressspinner';
|
||||||
|
|
||||||
const MDDisplay = dynamic(
|
const MDDisplay = dynamic(
|
||||||
() => import("@uiw/react-markdown-preview"),
|
() => import("@uiw/react-markdown-preview"),
|
||||||
@ -22,7 +23,7 @@ const MDDisplay = dynamic(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export default function CourseDetails({ processedEvent, paidCourse, decryptedContent, handlePaymentSuccess, handlePaymentError }) {
|
export default function CourseDetails({ processedEvent, paidCourse, lessons, decryptionPerformed, handlePaymentSuccess, handlePaymentError }) {
|
||||||
const [author, setAuthor] = useState(null);
|
const [author, setAuthor] = useState(null);
|
||||||
const [nAddress, setNAddress] = useState(null);
|
const [nAddress, setNAddress] = useState(null);
|
||||||
const [zapAmount, setZapAmount] = useState(0);
|
const [zapAmount, setZapAmount] = useState(0);
|
||||||
@ -45,6 +46,10 @@ export default function CourseDetails({ processedEvent, paidCourse, decryptedCon
|
|||||||
console.log("paidCourse", paidCourse);
|
console.log("paidCourse", paidCourse);
|
||||||
}, [paidCourse]);
|
}, [paidCourse]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("decryptionPerformed", decryptionPerformed);
|
||||||
|
}, [decryptionPerformed]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (session) {
|
if (session) {
|
||||||
setUser(session.user);
|
setUser(session.user);
|
||||||
@ -86,6 +91,14 @@ export default function CourseDetails({ processedEvent, paidCourse, decryptedCon
|
|||||||
setZapAmount(total);
|
setZapAmount(total);
|
||||||
}, [zaps, processedEvent]);
|
}, [zaps, processedEvent]);
|
||||||
|
|
||||||
|
if (!processedEvent || !author) {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center items-center h-screen">
|
||||||
|
<ProgressSpinner />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full px-24 pt-12 mx-auto mt-4 max-tab:px-0 max-mob:px-0 max-tab:pt-2 max-mob:pt-2'>
|
<div className='w-full px-24 pt-12 mx-auto mt-4 max-tab:px-0 max-mob:px-0 max-tab:pt-2 max-mob:pt-2'>
|
||||||
<div className='w-full flex flex-row justify-between max-tab:flex-col max-mob:flex-col'>
|
<div className='w-full flex flex-row justify-between max-tab:flex-col max-mob:flex-col'>
|
||||||
@ -128,8 +141,8 @@ export default function CourseDetails({ processedEvent, paidCourse, decryptedCon
|
|||||||
className="w-[344px] h-[194px] object-cover object-top rounded-lg"
|
className="w-[344px] h-[194px] object-cover object-top rounded-lg"
|
||||||
/>
|
/>
|
||||||
<div className='w-full flex justify-between items-center'>
|
<div className='w-full flex justify-between items-center'>
|
||||||
{paidCourse && !decryptedContent && (
|
{paidCourse && !decryptionPerformed && (
|
||||||
<ResourcePaymentButton
|
<CoursePaymentButton
|
||||||
lnAddress={'bitcoinplebdev@stacker.news'}
|
lnAddress={'bitcoinplebdev@stacker.news'}
|
||||||
amount={processedEvent.price}
|
amount={processedEvent.price}
|
||||||
onSuccess={handlePaymentSuccess}
|
onSuccess={handlePaymentSuccess}
|
||||||
@ -137,7 +150,7 @@ export default function CourseDetails({ processedEvent, paidCourse, decryptedCon
|
|||||||
resourceId={processedEvent.d}
|
resourceId={processedEvent.d}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{paidCourse && decryptedContent && author && processedEvent?.pubkey !== session?.user?.pubkey && (
|
{paidCourse && decryptionPerformed && author && processedEvent?.pubkey !== session?.user?.pubkey && (
|
||||||
<p className='text-green-500'>Paid {processedEvent.price} sats</p>
|
<p className='text-green-500'>Paid {processedEvent.price} sats</p>
|
||||||
)}
|
)}
|
||||||
{paidCourse && author && processedEvent?.pubkey === session?.user?.pubkey && (
|
{paidCourse && author && processedEvent?.pubkey === session?.user?.pubkey && (
|
||||||
|
@ -10,14 +10,6 @@ const ContentListItem = (content) => {
|
|||||||
const isDraft = Object.keys(content).includes('type');
|
const isDraft = Object.keys(content).includes('type');
|
||||||
const isCourse = content && content?.kind === 30004;
|
const isCourse = content && content?.kind === 30004;
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (content && content?.kind === 30004) {
|
|
||||||
console.log("isDraft", isDraft);
|
|
||||||
console.log("content", content);
|
|
||||||
console.log("isCourse", isCourse);
|
|
||||||
}
|
|
||||||
}, [content, isDraft, isCourse]);
|
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
let path = '';
|
let path = '';
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ import 'primeicons/primeicons.css';
|
|||||||
const CourseForm = ({ draft = null, isPublished = false }) => {
|
const CourseForm = ({ draft = null, isPublished = false }) => {
|
||||||
const [title, setTitle] = useState('');
|
const [title, setTitle] = useState('');
|
||||||
const [summary, setSummary] = useState('');
|
const [summary, setSummary] = useState('');
|
||||||
const [checked, setChecked] = useState(false);
|
const [isPaidCourse, setIsPaidCourse] = useState(draft?.price ? true : false);
|
||||||
const [price, setPrice] = useState(0);
|
const [price, setPrice] = useState(draft?.price || 0);
|
||||||
const [coverImage, setCoverImage] = useState('');
|
const [coverImage, setCoverImage] = useState('');
|
||||||
const [lessons, setLessons] = useState([{ id: uuidv4(), title: 'Select a lesson' }]);
|
const [lessons, setLessons] = useState([{ id: uuidv4(), title: 'Select a lesson' }]);
|
||||||
const [loadingLessons, setLoadingLessons] = useState(true);
|
const [loadingLessons, setLoadingLessons] = useState(true);
|
||||||
@ -89,7 +89,7 @@ const CourseForm = ({ draft = null, isPublished = false }) => {
|
|||||||
console.log('draft:', draft);
|
console.log('draft:', draft);
|
||||||
setTitle(draft.title);
|
setTitle(draft.title);
|
||||||
setSummary(draft.summary);
|
setSummary(draft.summary);
|
||||||
setChecked(draft.price > 0);
|
setIsPaidCourse(draft.price > 0);
|
||||||
setPrice(draft.price || 0);
|
setPrice(draft.price || 0);
|
||||||
setCoverImage(draft.image);
|
setCoverImage(draft.image);
|
||||||
// setSelectedLessons(draft.resources || []);
|
// setSelectedLessons(draft.resources || []);
|
||||||
@ -97,6 +97,10 @@ const CourseForm = ({ draft = null, isPublished = false }) => {
|
|||||||
}
|
}
|
||||||
}, [draft]);
|
}, [draft]);
|
||||||
|
|
||||||
|
const handlePriceChange = (value) => {
|
||||||
|
setPrice(value);
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -198,12 +202,20 @@ const CourseForm = ({ draft = null, isPublished = false }) => {
|
|||||||
if (resourcesLoading || !resources || workshopsLoading || !workshops || draftsLoading || !drafts) {
|
if (resourcesLoading || !resources || workshopsLoading || !workshops || draftsLoading || !drafts) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const draftOptions = drafts.map(draft => ({
|
|
||||||
|
const filterContent = (content) => {
|
||||||
|
console.log('contentttttt', content);
|
||||||
|
// If there is price in content.tags, then it is a paid content 'price' in the 0 index and stringified int in the 1 index
|
||||||
|
const contentPrice = content.tags.find(tag => tag[0] === 'price') ? parseInt(content.tags.find(tag => tag[0] === 'price')[1]) : 0;
|
||||||
|
return isPaidCourse ? contentPrice > 0 : contentPrice === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const draftOptions = drafts.filter(filterContent).map(draft => ({
|
||||||
label: <ContentDropdownItem content={draft} onSelect={(content) => handleLessonSelect(content, index)} selected={lessons[index] && lessons[index].id === draft.id} />,
|
label: <ContentDropdownItem content={draft} onSelect={(content) => handleLessonSelect(content, index)} selected={lessons[index] && lessons[index].id === draft.id} />,
|
||||||
value: draft.id
|
value: draft.id
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const resourceOptions = resources.map(resource => {
|
const resourceOptions = resources.filter(filterContent).map(resource => {
|
||||||
const { id, kind, pubkey, content, title, summary, image, published_at, d, topics } = parseEvent(resource);
|
const { id, kind, pubkey, content, title, summary, image, published_at, d, topics } = parseEvent(resource);
|
||||||
return {
|
return {
|
||||||
label: <ContentDropdownItem content={{ id, kind, pubkey, content, title, summary, image, published_at, d, topics }} onSelect={(content) => handleLessonSelect(content, index)} selected={lessons[index] && lessons[index].id === id} />,
|
label: <ContentDropdownItem content={{ id, kind, pubkey, content, title, summary, image, published_at, d, topics }} onSelect={(content) => handleLessonSelect(content, index)} selected={lessons[index] && lessons[index].id === id} />,
|
||||||
@ -211,7 +223,7 @@ const CourseForm = ({ draft = null, isPublished = false }) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const workshopOptions = workshops.map(workshop => {
|
const workshopOptions = workshops.filter(filterContent).map(workshop => {
|
||||||
const { id, kind, pubkey, content, title, summary, image, published_at, d, topics } = parseEvent(workshop);
|
const { id, kind, pubkey, content, title, summary, image, published_at, d, topics } = parseEvent(workshop);
|
||||||
return {
|
return {
|
||||||
label: <ContentDropdownItem content={{ id, kind, pubkey, content, title, summary, image, published_at, d, topics }} onSelect={(content) => handleLessonSelect(content, index)} selected={lessons[index] && lessons[index].id === id} />,
|
label: <ContentDropdownItem content={{ id, kind, pubkey, content, title, summary, image, published_at, d, topics }} onSelect={(content) => handleLessonSelect(content, index)} selected={lessons[index] && lessons[index].id === id} />,
|
||||||
@ -251,12 +263,17 @@ const CourseForm = ({ draft = null, isPublished = false }) => {
|
|||||||
<div className="p-inputgroup flex-1 mt-4">
|
<div className="p-inputgroup flex-1 mt-4">
|
||||||
<InputText value={coverImage} onChange={(e) => setCoverImage(e.target.value)} placeholder="Cover Image URL" />
|
<InputText value={coverImage} onChange={(e) => setCoverImage(e.target.value)} placeholder="Cover Image URL" />
|
||||||
</div>
|
</div>
|
||||||
<div className="p-inputgroup flex-1 mt-4 flex-col">
|
<div className="p-inputgroup flex-1 mt-8 flex-col">
|
||||||
<p className="py-2">Paid Course</p>
|
<p className="py-2">Paid Course</p>
|
||||||
<InputSwitch checked={checked} onChange={(e) => setChecked(e.value)} />
|
<InputSwitch checked={isPaidCourse} onChange={(e) => setIsPaidCourse(e.value)} />
|
||||||
{checked && (
|
{isPaidCourse && (
|
||||||
<div className="p-inputgroup flex-1 py-4">
|
<div className="p-inputgroup flex-1 py-4">
|
||||||
<InputNumber value={price} onValueChange={(e) => setPrice(e.value)} placeholder="Price (sats)" />
|
<InputNumber
|
||||||
|
value={price}
|
||||||
|
onValueChange={(e) => handlePriceChange(e.value)}
|
||||||
|
placeholder="Price (sats)"
|
||||||
|
min={1}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,6 +25,7 @@ const EditCourseForm = ({ draft }) => {
|
|||||||
const [summary, setSummary] = useState('');
|
const [summary, setSummary] = useState('');
|
||||||
const [checked, setChecked] = useState(false);
|
const [checked, setChecked] = useState(false);
|
||||||
const [price, setPrice] = useState(0);
|
const [price, setPrice] = useState(0);
|
||||||
|
const [isPaid, setIsPaid] = useState(false);
|
||||||
const [coverImage, setCoverImage] = useState('');
|
const [coverImage, setCoverImage] = useState('');
|
||||||
const [selectedLessons, setSelectedLessons] = useState([]);
|
const [selectedLessons, setSelectedLessons] = useState([]);
|
||||||
const [selectedLessonsLoading, setSelectedLessonsLoading] = useState(false);
|
const [selectedLessonsLoading, setSelectedLessonsLoading] = useState(false);
|
||||||
@ -63,11 +64,17 @@ const EditCourseForm = ({ draft }) => {
|
|||||||
setSummary(draft.summary);
|
setSummary(draft.summary);
|
||||||
setChecked(draft.price > 0);
|
setChecked(draft.price > 0);
|
||||||
setPrice(draft.price || 0);
|
setPrice(draft.price || 0);
|
||||||
|
setIsPaid(draft.price > 0);
|
||||||
setCoverImage(draft.image);
|
setCoverImage(draft.image);
|
||||||
setTopics(draft.topics || ['']);
|
setTopics(draft.topics || ['']);
|
||||||
}
|
}
|
||||||
}, [draft, ndk, showToast, parseEvent]);
|
}, [draft, ndk, showToast, parseEvent]);
|
||||||
|
|
||||||
|
const handlePriceChange = (value) => {
|
||||||
|
setPrice(value);
|
||||||
|
setIsPaid(value > 0);
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -90,7 +97,7 @@ const EditCourseForm = ({ draft }) => {
|
|||||||
title,
|
title,
|
||||||
summary,
|
summary,
|
||||||
image: coverImage,
|
image: coverImage,
|
||||||
price: checked ? price : 0,
|
price: isPaid ? price : 0,
|
||||||
topics,
|
topics,
|
||||||
resourceIds: lessonsToUpdate.filter(lesson => lesson && lesson.id).map(lesson => lesson.id)
|
resourceIds: lessonsToUpdate.filter(lesson => lesson && lesson.id).map(lesson => lesson.id)
|
||||||
};
|
};
|
||||||
@ -137,7 +144,12 @@ const EditCourseForm = ({ draft }) => {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const resourceOptions = resources.map(resource => {
|
const filterContent = (content) => {
|
||||||
|
const contentPrice = content.price || 0;
|
||||||
|
return isPaid ? contentPrice > 0 : contentPrice === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const resourceOptions = resources.filter(filterContent).map(resource => {
|
||||||
const parsedResource = parseEvent(resource);
|
const parsedResource = parseEvent(resource);
|
||||||
return {
|
return {
|
||||||
label: <ContentDropdownItem content={parsedResource} onSelect={handleLessonSelect} selected={selectedLessons.some(lesson => lesson.id === parsedResource.id)} />,
|
label: <ContentDropdownItem content={parsedResource} onSelect={handleLessonSelect} selected={selectedLessons.some(lesson => lesson.id === parsedResource.id)} />,
|
||||||
@ -145,7 +157,7 @@ const EditCourseForm = ({ draft }) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const workshopOptions = workshops.map(workshop => {
|
const workshopOptions = workshops.filter(filterContent).map(workshop => {
|
||||||
const parsedWorkshop = parseEvent(workshop);
|
const parsedWorkshop = parseEvent(workshop);
|
||||||
return {
|
return {
|
||||||
label: <ContentDropdownItem content={parsedWorkshop} onSelect={handleLessonSelect} selected={selectedLessons.some(lesson => lesson.id === parsedWorkshop.id)} />,
|
label: <ContentDropdownItem content={parsedWorkshop} onSelect={handleLessonSelect} selected={selectedLessons.some(lesson => lesson.id === parsedWorkshop.id)} />,
|
||||||
@ -179,7 +191,7 @@ const EditCourseForm = ({ draft }) => {
|
|||||||
<InputSwitch checked={checked} onChange={(e) => setChecked(e.value)} />
|
<InputSwitch checked={checked} onChange={(e) => setChecked(e.value)} />
|
||||||
{checked && (
|
{checked && (
|
||||||
<div className="p-inputgroup flex-1 py-4">
|
<div className="p-inputgroup flex-1 py-4">
|
||||||
<InputNumber value={price} onValueChange={(e) => setPrice(e.value)} placeholder="Price (sats)" />
|
<InputNumber value={price} onValueChange={(e) => handlePriceChange(e.value)} placeholder="Price (sats)" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,7 @@ import { useNDKContext } from "@/context/NDKContext";
|
|||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
import { nip04 } from 'nostr-tools';
|
import { nip04 } from 'nostr-tools';
|
||||||
|
import { ProgressSpinner } from 'primereact/progressspinner';
|
||||||
|
|
||||||
const MDDisplay = dynamic(
|
const MDDisplay = dynamic(
|
||||||
() => import("@uiw/react-markdown-preview"),
|
() => import("@uiw/react-markdown-preview"),
|
||||||
@ -21,12 +22,13 @@ const Course = () => {
|
|||||||
const [lessonIds, setLessonIds] = useState([]);
|
const [lessonIds, setLessonIds] = useState([]);
|
||||||
const [lessons, setLessons] = useState([]);
|
const [lessons, setLessons] = useState([]);
|
||||||
const [paidCourse, setPaidCourse] = useState(false);
|
const [paidCourse, setPaidCourse] = useState(false);
|
||||||
const [decryptedContent, setDecryptedContent] = useState(null);
|
const [decryptionPerformed, setDecryptionPerformed] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const {ndk, addSigner} = useNDKContext();
|
const {ndk, addSigner} = useNDKContext();
|
||||||
const { data: session, update } = useSession();
|
const { data: session, update } = useSession();
|
||||||
const { showToast } = useToast();
|
const { showToast } = useToast();
|
||||||
|
|
||||||
const privkey = process.env.NEXT_PUBLIC_APP_PRIV_KEY;
|
const privkey = process.env.NEXT_PUBLIC_APP_PRIV_KEY;
|
||||||
const pubkey = process.env.NEXT_PUBLIC_APP_PUBLIC_KEY;
|
const pubkey = process.env.NEXT_PUBLIC_APP_PUBLIC_KEY;
|
||||||
|
|
||||||
@ -112,21 +114,37 @@ const Course = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const decryptContent = async () => {
|
const decryptContent = async () => {
|
||||||
if (session?.user && paidCourse) {
|
if (session?.user && paidCourse && !decryptionPerformed) {
|
||||||
if (session.user?.purchased?.length > 0) {
|
setLoading(true);
|
||||||
const purchasedCourse = session.user.purchased.find(purchase => purchase.resourceId === course.d);
|
const canAccess =
|
||||||
if (purchasedCourse) {
|
session.user.purchased?.some(purchase => purchase.courseId === course?.d) ||
|
||||||
const decryptedContent = await nip04.decrypt(privkey, pubkey, course.content);
|
session.user?.role?.subscribed ||
|
||||||
setDecryptedContent(decryptedContent);
|
session.user?.pubkey === course?.pubkey;
|
||||||
}
|
|
||||||
} else if (session.user?.role && session.user.role.subscribed) {
|
if (canAccess && lessons.length > 0) {
|
||||||
const decryptedContent = await nip04.decrypt(privkey, pubkey, course.content);
|
try {
|
||||||
setDecryptedContent(decryptedContent);
|
const decryptedLessons = await Promise.all(lessons.map(async (lesson) => {
|
||||||
|
const decryptedContent = await nip04.decrypt(privkey, pubkey, lesson.content);
|
||||||
|
return { ...lesson, content: decryptedContent };
|
||||||
|
}));
|
||||||
|
setLessons(decryptedLessons);
|
||||||
|
setDecryptionPerformed(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error decrypting lessons:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
decryptContent();
|
decryptContent();
|
||||||
}, [session, paidCourse, course]);
|
}, [session, paidCourse, course, lessons, privkey, pubkey, decryptionPerformed]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (course && lessons.length > 0 && (!paidCourse || decryptionPerformed)) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}, [course, lessons, paidCourse, decryptionPerformed]);
|
||||||
|
|
||||||
const handlePaymentSuccess = async (response, newCourse) => {
|
const handlePaymentSuccess = async (response, newCourse) => {
|
||||||
if (response && response?.preimage) {
|
if (response && response?.preimage) {
|
||||||
@ -142,12 +160,21 @@ const Course = () => {
|
|||||||
showToast('error', 'Payment Error', `Failed to purchase course. Please try again. Error: ${error}`);
|
showToast('error', 'Payment Error', `Failed to purchase course. Please try again. Error: ${error}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center items-center h-screen">
|
||||||
|
<ProgressSpinner />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CourseDetails
|
<CourseDetails
|
||||||
processedEvent={course}
|
processedEvent={course}
|
||||||
paidCourse={paidCourse}
|
paidCourse={paidCourse}
|
||||||
decryptedContent={decryptedContent}
|
lessons={lessons}
|
||||||
|
decryptionPerformed={decryptionPerformed}
|
||||||
handlePaymentSuccess={handlePaymentSuccess}
|
handlePaymentSuccess={handlePaymentSuccess}
|
||||||
handlePaymentError={handlePaymentError}
|
handlePaymentError={handlePaymentError}
|
||||||
/>
|
/>
|
||||||
@ -155,9 +182,7 @@ const Course = () => {
|
|||||||
<CourseLesson key={index} lesson={lesson} course={course} />
|
<CourseLesson key={index} lesson={lesson} course={course} />
|
||||||
))}
|
))}
|
||||||
<div className="mx-auto my-6">
|
<div className="mx-auto my-6">
|
||||||
{
|
{course?.content && <MDDisplay source={course.content} />}
|
||||||
course?.content && <MDDisplay source={course.content} />
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -227,26 +227,11 @@ export default function Draft() {
|
|||||||
['image', draft.image],
|
['image', draft.image],
|
||||||
...draft.topics.map(topic => ['t', topic]),
|
...draft.topics.map(topic => ['t', topic]),
|
||||||
['published_at', Math.floor(Date.now() / 1000).toString()],
|
['published_at', Math.floor(Date.now() / 1000).toString()],
|
||||||
|
...(draft?.price ? [['price', draft.price.toString()], ['location', `https://plebdevs.com/details/${draft.id}`]] : []),
|
||||||
];
|
];
|
||||||
|
|
||||||
type = 'workshop';
|
type = 'workshop';
|
||||||
break;
|
break;
|
||||||
case 'course':
|
|
||||||
event.kind = 30023;
|
|
||||||
event.content = draft.content;
|
|
||||||
event.created_at = Math.floor(Date.now() / 1000);
|
|
||||||
event.pubkey = user.pubkey;
|
|
||||||
event.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:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user