2024-09-15 13:27:37 -05:00
|
|
|
import { useState, useEffect } from "react";
|
|
|
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
|
2024-08-25 14:58:25 -05:00
|
|
|
import { Tag } from "primereact/tag";
|
2024-09-15 13:27:37 -05:00
|
|
|
import ZapDisplay from "@/components/zaps/ZapDisplay";
|
|
|
|
import { nip19 } from "nostr-tools";
|
|
|
|
import Image from "next/image"
|
2024-08-13 14:42:36 -05:00
|
|
|
import { useZapsSubscription } from "@/hooks/nostrQueries/zaps/useZapsSubscription";
|
2024-09-15 13:27:37 -05:00
|
|
|
import { getTotalFromZaps } from "@/utils/lightning";
|
|
|
|
import { useImageProxy } from "@/hooks/useImageProxy";
|
|
|
|
import { useRouter } from "next/router";
|
|
|
|
import { formatTimestampToHowLongAgo } from "@/utils/time";
|
|
|
|
import { ProgressSpinner } from "primereact/progressspinner";
|
2024-10-12 14:27:13 -05:00
|
|
|
import { Message } from "primereact/message";
|
2024-10-12 14:41:23 -05:00
|
|
|
import useWindowWidth from "@/hooks/useWindowWidth";
|
2024-09-15 13:27:37 -05:00
|
|
|
import GenericButton from "@/components/buttons/GenericButton";
|
2024-09-17 13:55:51 -05:00
|
|
|
import appConfig from "@/config/appConfig";
|
2024-03-26 18:14:32 -05:00
|
|
|
|
2024-10-16 20:14:40 -05:00
|
|
|
export function CourseTemplate({ course }) {
|
2024-08-25 18:15:45 -05:00
|
|
|
const { zaps, zapsLoading, zapsError } = useZapsSubscription({ event: course });
|
|
|
|
const [zapAmount, setZapAmount] = useState(0);
|
2024-09-15 13:27:37 -05:00
|
|
|
const [lessonCount, setLessonCount] = useState(0);
|
|
|
|
const [nAddress, setNAddress] = useState(null);
|
2024-08-05 17:27:19 -05:00
|
|
|
const router = useRouter();
|
|
|
|
const { returnImageProxy } = useImageProxy();
|
2024-10-12 14:41:23 -05:00
|
|
|
const windowWidth = useWindowWidth();
|
|
|
|
const isMobile = windowWidth < 768;
|
2024-03-27 18:12:17 -05:00
|
|
|
|
2024-08-05 17:27:19 -05:00
|
|
|
useEffect(() => {
|
2024-08-25 18:15:45 -05:00
|
|
|
if (zaps.length > 0) {
|
|
|
|
const total = getTotalFromZaps(zaps, course);
|
|
|
|
setZapAmount(total);
|
|
|
|
}
|
2024-10-16 20:14:40 -05:00
|
|
|
}, [zaps, course]);
|
2024-08-04 18:16:56 -05:00
|
|
|
|
2024-09-15 13:27:37 -05:00
|
|
|
useEffect(() => {
|
|
|
|
if (course && course?.tags) {
|
|
|
|
const lessons = course.tags.filter(tag => tag[0] === "a");
|
|
|
|
setLessonCount(lessons.length);
|
|
|
|
}
|
|
|
|
}, [course]);
|
|
|
|
|
2024-10-16 19:46:59 -05:00
|
|
|
console.log(nip19.decode("naddr1qvzqqqr4gupzpueu32tp0jc47uzlcuxdgcw06m40ytu7ynpna2adnqty3e0vda6pqpqryvrxxyun2vnrxasngvt98q6rycfs8ycrvvpjx5mrjdpkvs6ryef38qmngcnpv4jkyd3nxcmxvvpkvgmrydpcxqmxxdfhvsckxctpvs42mx08"))
|
|
|
|
|
2024-09-15 13:27:37 -05:00
|
|
|
useEffect(() => {
|
|
|
|
if (course && course?.id) {
|
|
|
|
const nAddress = nip19.naddrEncode({
|
|
|
|
pubkey: course.pubkey,
|
|
|
|
kind: course.kind,
|
|
|
|
identifier: course.id,
|
2024-09-17 13:55:51 -05:00
|
|
|
relayUrls: appConfig.defaultRelayUrls
|
2024-09-15 13:27:37 -05:00
|
|
|
});
|
|
|
|
setNAddress(nAddress);
|
|
|
|
}
|
|
|
|
}, [course]);
|
|
|
|
|
2024-09-17 13:28:58 -05:00
|
|
|
if (!nAddress) return <div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
2024-09-15 13:27:37 -05:00
|
|
|
|
2024-08-05 17:27:19 -05:00
|
|
|
if (zapsError) return <div>Error: {zapsError}</div>;
|
2024-04-23 18:52:55 -05:00
|
|
|
|
2024-08-05 17:27:19 -05:00
|
|
|
return (
|
2024-09-15 13:27:37 -05:00
|
|
|
<Card className="overflow-hidden group hover:shadow-xl transition-all duration-300 bg-gray-800 m-2 border-none">
|
2024-10-14 10:27:23 -05:00
|
|
|
<div
|
|
|
|
className="relative w-full h-0"
|
|
|
|
style={{ paddingBottom: "56.25%" }}
|
|
|
|
>
|
2024-08-05 17:27:19 -05:00
|
|
|
<Image
|
2024-10-14 15:20:35 -05:00
|
|
|
alt="video thumbnail"
|
2024-08-05 17:27:19 -05:00
|
|
|
src={returnImageProxy(course.image)}
|
|
|
|
quality={100}
|
|
|
|
layout="fill"
|
2024-10-14 10:27:23 -05:00
|
|
|
objectFit="cover"
|
|
|
|
className="rounded-md"
|
2024-08-05 17:27:19 -05:00
|
|
|
/>
|
2024-09-15 13:27:37 -05:00
|
|
|
<div className="absolute inset-0 bg-gradient-to-br from-primary/80 to-primary-foreground/50" />
|
2024-10-14 15:20:35 -05:00
|
|
|
<div className="absolute top-4 right-4 flex items-center gap-1 bg-black/50 text-white px-3 py-1 rounded-full">
|
2024-09-15 13:27:37 -05:00
|
|
|
<ZapDisplay zapAmount={zapAmount} event={course} zapsLoading={zapsLoading && zapAmount === 0} />
|
2024-03-26 18:14:32 -05:00
|
|
|
</div>
|
2024-09-15 13:27:37 -05:00
|
|
|
<CardHeader className="absolute bottom-[-8px] left-0 right-0 text-white bg-gray-800/70 w-fit rounded-lg rounded-bl-none rounded-tl-none rounded-br-none p-4 max-w-[70%] max-h-[60%]">
|
|
|
|
<div className="flex items-center justify-center gap-4">
|
|
|
|
<i className="pi pi-book text-2xl text-[#f8f8ff]"></i>
|
|
|
|
<div>
|
2024-10-17 09:05:58 -05:00
|
|
|
<CardTitle className="text-xl sm:text-2xl mb-2">{course.name}</CardTitle>
|
2024-09-15 13:27:37 -05:00
|
|
|
</div>
|
2024-08-25 14:58:25 -05:00
|
|
|
</div>
|
2024-09-15 13:27:37 -05:00
|
|
|
</CardHeader>
|
2024-08-05 17:27:19 -05:00
|
|
|
</div>
|
2024-10-14 19:12:20 -05:00
|
|
|
<CardContent className={`${isMobile ? "px-3" : ""} pt-6 pb-2 w-full flex flex-row justify-between items-start`}>
|
|
|
|
<div className="flex flex-wrap gap-2 max-w-[65%]">
|
2024-09-15 13:27:37 -05:00
|
|
|
{course && course.topics && course.topics.map((topic, index) => (
|
2024-10-14 10:42:19 -05:00
|
|
|
<Tag size="small" key={index} className="px-2 py-1 text-sm text-[#f8f8ff]">
|
2024-09-15 13:27:37 -05:00
|
|
|
{topic}
|
|
|
|
</Tag>
|
|
|
|
))}
|
|
|
|
</div>
|
2024-10-14 15:20:35 -05:00
|
|
|
<div className="flex flex-col items-end">
|
|
|
|
<p className="font-bold text-gray-300">{lessonCount} {lessonCount === 1 ? "lesson" : "lessons"}</p>
|
2024-10-12 14:27:13 -05:00
|
|
|
<div className="flex flex-col items-end">
|
|
|
|
{
|
|
|
|
course?.price && course?.price > 0 ? (
|
2024-10-13 19:41:15 -05:00
|
|
|
<Message className={`${isMobile ? "py-1 text-xs" : "py-2"} whitespace-nowrap`} icon="pi pi-lock" severity="info" text={`${course.price} sats`} />
|
2024-10-12 14:27:13 -05:00
|
|
|
) : (
|
2024-10-13 19:41:15 -05:00
|
|
|
<Message className={`${isMobile ? "py-1 text-xs" : "py-2"} whitespace-nowrap`} icon="pi pi-lock-open" severity="success" text="Free" />
|
2024-10-12 14:27:13 -05:00
|
|
|
)
|
|
|
|
}
|
|
|
|
</div>
|
|
|
|
</div>
|
2024-10-14 15:20:35 -05:00
|
|
|
</CardContent>
|
|
|
|
<CardDescription className={`${isMobile ? "w-full p-3" : "p-6"} py-2 pt-0 text-base text-neutral-50/90 dark:text-neutral-900/90 overflow-hidden min-h-[4em] flex items-center max-w-[100%]`}
|
|
|
|
style={{
|
|
|
|
overflow: "hidden",
|
|
|
|
display: "-webkit-box",
|
|
|
|
WebkitBoxOrient: "vertical",
|
|
|
|
WebkitLineClamp: "2"
|
|
|
|
}}>
|
|
|
|
<p className="line-clamp-2 text-wrap break-words">{(course.summary || course.description)?.split('\n').map((line, index) => (
|
|
|
|
<span className="text-wrap break-words" key={index}>{line}</span>
|
|
|
|
))}</p>
|
2024-09-15 13:27:37 -05:00
|
|
|
</CardDescription>
|
2024-10-12 17:40:13 -05:00
|
|
|
<CardFooter className={`flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 border-t border-gray-700 pt-4 ${isMobile ? "px-3" : ""}`}>
|
2024-09-15 13:27:37 -05:00
|
|
|
<p className="text-sm text-gray-300">{course?.published_at && course.published_at !== "" ? (
|
|
|
|
formatTimestampToHowLongAgo(course.published_at)
|
|
|
|
) : (
|
|
|
|
formatTimestampToHowLongAgo(course.created_at)
|
|
|
|
)}</p>
|
|
|
|
<GenericButton onClick={() => router.push(`/course/${nAddress}`)} size="small" label="Start Learning" icon="pi pi-chevron-right" iconPos="right" outlined className="items-center py-2" />
|
|
|
|
</CardFooter>
|
|
|
|
</Card>
|
|
|
|
)
|
2024-10-12 17:00:46 -05:00
|
|
|
}
|