mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-04-19 10:51:20 +00:00
Add checks for user logged in, paid course and or subscriber for user being able to mark lesson as completed
This commit is contained in:
parent
79b8cf1ff8
commit
5c6bf72a99
@ -14,6 +14,7 @@ import useTrackVideoLesson from '@/hooks/tracking/useTrackVideoLesson';
|
||||
import { Menu } from "primereact/menu";
|
||||
import { Toast } from "primereact/toast";
|
||||
import MoreOptionsMenu from "@/components/ui/MoreOptionsMenu";
|
||||
import { useSession } from "next-auth/react";
|
||||
|
||||
const MDDisplay = dynamic(
|
||||
() => import("@uiw/react-markdown-preview"),
|
||||
@ -35,6 +36,7 @@ const CombinedLesson = ({ lesson, course, decryptionPerformed, isPaid, setComple
|
||||
const windowWidth = useWindowWidth();
|
||||
const isMobileView = windowWidth <= 768;
|
||||
const isVideo = lesson?.type === 'video';
|
||||
const { data: session } = useSession();
|
||||
|
||||
const { isCompleted: videoCompleted, isTracking: videoTracking, markLessonAsCompleted } = useTrackVideoLesson({
|
||||
lessonId: lesson?.d,
|
||||
@ -45,46 +47,60 @@ const CombinedLesson = ({ lesson, course, decryptionPerformed, isPaid, setComple
|
||||
decryptionPerformed
|
||||
});
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
label: 'Mark as completed',
|
||||
icon: 'pi pi-check-circle',
|
||||
command: async () => {
|
||||
try {
|
||||
await markLessonAsCompleted();
|
||||
setCompleted(lesson.id);
|
||||
toastRef.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Success',
|
||||
detail: 'Lesson marked as completed',
|
||||
life: 3000
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to mark lesson as completed:', error);
|
||||
toastRef.current.show({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Failed to mark lesson as completed',
|
||||
life: 3000
|
||||
});
|
||||
const buildMenuItems = () => {
|
||||
const items = [];
|
||||
|
||||
const hasAccess = session?.user && (
|
||||
!isPaid ||
|
||||
decryptionPerformed ||
|
||||
session.user.role?.subscribed
|
||||
);
|
||||
|
||||
if (hasAccess) {
|
||||
items.push({
|
||||
label: 'Mark as completed',
|
||||
icon: 'pi pi-check-circle',
|
||||
command: async () => {
|
||||
try {
|
||||
await markLessonAsCompleted();
|
||||
setCompleted(lesson.id);
|
||||
toastRef.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Success',
|
||||
detail: 'Lesson marked as completed',
|
||||
life: 3000
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to mark lesson as completed:', error);
|
||||
toastRef.current.show({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Failed to mark lesson as completed',
|
||||
life: 3000
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
label: 'Open lesson',
|
||||
icon: 'pi pi-arrow-up-right',
|
||||
command: () => {
|
||||
window.open(`/details/${lesson.id}`, '_blank');
|
||||
}
|
||||
},
|
||||
{
|
||||
});
|
||||
|
||||
items.push({
|
||||
label: 'View Nostr note',
|
||||
icon: 'pi pi-globe',
|
||||
command: () => {
|
||||
window.open(`https://habla.news/a/${nAddress}`, '_blank');
|
||||
}
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleYouTubeMessage = (event) => {
|
||||
@ -270,7 +286,7 @@ const CombinedLesson = ({ lesson, course, decryptionPerformed, isPaid, setComple
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<MoreOptionsMenu
|
||||
menuItems={menuItems}
|
||||
menuItems={buildMenuItems()}
|
||||
additionalLinks={lesson?.additionalLinks || []}
|
||||
isMobileView={isMobileView}
|
||||
/>
|
||||
|
@ -12,6 +12,7 @@ import useWindowWidth from "@/hooks/useWindowWidth";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import appConfig from "@/config/appConfig";
|
||||
import MoreOptionsMenu from "@/components/ui/MoreOptionsMenu";
|
||||
import { useSession } from "next-auth/react";
|
||||
|
||||
const MDDisplay = dynamic(
|
||||
() => import("@uiw/react-markdown-preview"),
|
||||
@ -28,6 +29,7 @@ const CourseLesson = ({ lesson, course, decryptionPerformed, isPaid, setComplete
|
||||
const toastRef = useRef(null);
|
||||
const windowWidth = useWindowWidth();
|
||||
const isMobileView = windowWidth <= 768;
|
||||
const { data: session } = useSession();
|
||||
|
||||
const readTime = lesson?.content ? Math.max(30, Math.ceil(lesson.content.length / 20)) : 60;
|
||||
|
||||
@ -39,39 +41,51 @@ const CourseLesson = ({ lesson, course, decryptionPerformed, isPaid, setComplete
|
||||
decryptionPerformed
|
||||
});
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
label: 'Mark as completed',
|
||||
icon: 'pi pi-check-circle',
|
||||
command: async () => {
|
||||
try {
|
||||
await markLessonAsCompleted();
|
||||
setCompleted && setCompleted(lesson.id);
|
||||
toastRef.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Success',
|
||||
detail: 'Lesson marked as completed',
|
||||
life: 3000
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to mark lesson as completed:', error);
|
||||
toastRef.current.show({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Failed to mark lesson as completed',
|
||||
life: 3000
|
||||
});
|
||||
const buildMenuItems = () => {
|
||||
const items = [];
|
||||
|
||||
const hasAccess = session?.user && (
|
||||
!isPaid ||
|
||||
decryptionPerformed ||
|
||||
session.user.role?.subscribed
|
||||
);
|
||||
|
||||
if (hasAccess) {
|
||||
items.push({
|
||||
label: 'Mark as completed',
|
||||
icon: 'pi pi-check-circle',
|
||||
command: async () => {
|
||||
try {
|
||||
await markLessonAsCompleted();
|
||||
setCompleted && setCompleted(lesson.id);
|
||||
toastRef.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Success',
|
||||
detail: 'Lesson marked as completed',
|
||||
life: 3000
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to mark lesson as completed:', error);
|
||||
toastRef.current.show({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Failed to mark lesson as completed',
|
||||
life: 3000
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
label: 'Open lesson',
|
||||
icon: 'pi pi-arrow-up-right',
|
||||
command: () => {
|
||||
window.open(`/details/${lesson.id}`, '_blank');
|
||||
}
|
||||
},
|
||||
{
|
||||
});
|
||||
|
||||
items.push({
|
||||
label: 'View Nostr note',
|
||||
icon: 'pi pi-globe',
|
||||
command: () => {
|
||||
@ -85,10 +99,10 @@ const CourseLesson = ({ lesson, course, decryptionPerformed, isPaid, setComplete
|
||||
window.open(`https://habla.news/a/${addr}`, '_blank');
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// Add additional links to menu items if they exist
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!zaps || zapsLoading || zapsError) return;
|
||||
@ -164,7 +178,7 @@ const CourseLesson = ({ lesson, course, decryptionPerformed, isPaid, setComplete
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<MoreOptionsMenu
|
||||
menuItems={menuItems}
|
||||
menuItems={buildMenuItems()}
|
||||
additionalLinks={lesson?.additionalLinks || []}
|
||||
isMobileView={isMobileView}
|
||||
/>
|
||||
|
@ -13,6 +13,7 @@ import appConfig from "@/config/appConfig";
|
||||
import useTrackDocumentLesson from "@/hooks/tracking/useTrackDocumentLesson";
|
||||
import { Toast } from "primereact/toast";
|
||||
import MoreOptionsMenu from "@/components/ui/MoreOptionsMenu";
|
||||
import { useSession } from "next-auth/react";
|
||||
|
||||
const MDDisplay = dynamic(
|
||||
() => import("@uiw/react-markdown-preview"),
|
||||
@ -32,6 +33,7 @@ const DocumentLesson = ({ lesson, course, decryptionPerformed, isPaid, setComple
|
||||
const toastRef = useRef(null);
|
||||
// todo implement real read time needs to be on form
|
||||
const readTime = 120;
|
||||
const { data: session } = useSession();
|
||||
|
||||
const { isCompleted, isTracking, markLessonAsCompleted } = useTrackDocumentLesson({
|
||||
lessonId: lesson?.d,
|
||||
@ -41,46 +43,60 @@ const DocumentLesson = ({ lesson, course, decryptionPerformed, isPaid, setComple
|
||||
decryptionPerformed: decryptionPerformed,
|
||||
});
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
label: 'Mark as completed',
|
||||
icon: 'pi pi-check-circle',
|
||||
command: async () => {
|
||||
try {
|
||||
await markLessonAsCompleted();
|
||||
setCompleted && setCompleted(lesson.id);
|
||||
toastRef.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Success',
|
||||
detail: 'Lesson marked as completed',
|
||||
life: 3000
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to mark lesson as completed:', error);
|
||||
toastRef.current.show({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Failed to mark lesson as completed',
|
||||
life: 3000
|
||||
});
|
||||
const buildMenuItems = () => {
|
||||
const items = [];
|
||||
|
||||
const hasAccess = session?.user && (
|
||||
!isPaid ||
|
||||
decryptionPerformed ||
|
||||
session.user.role?.subscribed
|
||||
);
|
||||
|
||||
if (hasAccess) {
|
||||
items.push({
|
||||
label: 'Mark as completed',
|
||||
icon: 'pi pi-check-circle',
|
||||
command: async () => {
|
||||
try {
|
||||
await markLessonAsCompleted();
|
||||
setCompleted && setCompleted(lesson.id);
|
||||
toastRef.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Success',
|
||||
detail: 'Lesson marked as completed',
|
||||
life: 3000
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to mark lesson as completed:', error);
|
||||
toastRef.current.show({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Failed to mark lesson as completed',
|
||||
life: 3000
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
label: 'Open lesson',
|
||||
icon: 'pi pi-arrow-up-right',
|
||||
command: () => {
|
||||
window.open(`/details/${lesson.id}`, '_blank');
|
||||
}
|
||||
},
|
||||
{
|
||||
});
|
||||
|
||||
items.push({
|
||||
label: 'View Nostr note',
|
||||
icon: 'pi pi-globe',
|
||||
command: () => {
|
||||
window.open(`https://habla.news/a/${nAddress}`, '_blank');
|
||||
}
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!zaps || zapsLoading || zapsError) return;
|
||||
@ -183,7 +199,7 @@ const DocumentLesson = ({ lesson, course, decryptionPerformed, isPaid, setComple
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<MoreOptionsMenu
|
||||
menuItems={menuItems}
|
||||
menuItems={buildMenuItems()}
|
||||
additionalLinks={lesson?.additionalLinks || []}
|
||||
isMobileView={isMobileView}
|
||||
/>
|
||||
|
@ -13,6 +13,7 @@ import useWindowWidth from "@/hooks/useWindowWidth";
|
||||
import useTrackVideoLesson from '@/hooks/tracking/useTrackVideoLesson';
|
||||
import { Toast } from "primereact/toast";
|
||||
import MoreOptionsMenu from "@/components/ui/MoreOptionsMenu";
|
||||
import { useSession } from "next-auth/react";
|
||||
|
||||
const MDDisplay = dynamic(
|
||||
() => import("@uiw/react-markdown-preview"),
|
||||
@ -33,6 +34,7 @@ const VideoLesson = ({ lesson, course, decryptionPerformed, isPaid, setCompleted
|
||||
const mdDisplayRef = useRef(null);
|
||||
const menuRef = useRef(null);
|
||||
const toastRef = useRef(null);
|
||||
const { data: session } = useSession();
|
||||
|
||||
const { isCompleted, isTracking, markLessonAsCompleted } = useTrackVideoLesson({
|
||||
lessonId: lesson?.d,
|
||||
@ -43,46 +45,60 @@ const VideoLesson = ({ lesson, course, decryptionPerformed, isPaid, setCompleted
|
||||
decryptionPerformed
|
||||
});
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
label: 'Mark as completed',
|
||||
icon: 'pi pi-check-circle',
|
||||
command: async () => {
|
||||
try {
|
||||
await markLessonAsCompleted();
|
||||
setCompleted(lesson.id);
|
||||
toastRef.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Success',
|
||||
detail: 'Lesson marked as completed',
|
||||
life: 3000
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to mark lesson as completed:', error);
|
||||
toastRef.current.show({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Failed to mark lesson as completed',
|
||||
life: 3000
|
||||
});
|
||||
const buildMenuItems = () => {
|
||||
const items = [];
|
||||
|
||||
const hasAccess = session?.user && (
|
||||
!isPaid ||
|
||||
decryptionPerformed ||
|
||||
session.user.role?.subscribed
|
||||
);
|
||||
|
||||
if (hasAccess) {
|
||||
items.push({
|
||||
label: 'Mark as completed',
|
||||
icon: 'pi pi-check-circle',
|
||||
command: async () => {
|
||||
try {
|
||||
await markLessonAsCompleted();
|
||||
setCompleted(lesson.id);
|
||||
toastRef.current.show({
|
||||
severity: 'success',
|
||||
summary: 'Success',
|
||||
detail: 'Lesson marked as completed',
|
||||
life: 3000
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to mark lesson as completed:', error);
|
||||
toastRef.current.show({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Failed to mark lesson as completed',
|
||||
life: 3000
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
label: 'Open lesson',
|
||||
icon: 'pi pi-arrow-up-right',
|
||||
command: () => {
|
||||
window.open(`/details/${lesson.id}`, '_blank');
|
||||
}
|
||||
},
|
||||
{
|
||||
});
|
||||
|
||||
items.push({
|
||||
label: 'View Nostr note',
|
||||
icon: 'pi pi-globe',
|
||||
command: () => {
|
||||
window.open(`https://habla.news/a/${nAddress}`, '_blank');
|
||||
}
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleYouTubeMessage = (event) => {
|
||||
@ -239,7 +255,7 @@ const VideoLesson = ({ lesson, course, decryptionPerformed, isPaid, setCompleted
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<MoreOptionsMenu
|
||||
menuItems={menuItems}
|
||||
menuItems={buildMenuItems()}
|
||||
additionalLinks={lesson?.additionalLinks || []}
|
||||
isMobileView={isMobileView}
|
||||
/>
|
||||
|
@ -141,7 +141,7 @@ const DocumentDetails = ({ processedEvent, topics, title, summary, image, price,
|
||||
return (
|
||||
<div className="w-full px-4">
|
||||
|
||||
<div className="w-full p-8 rounded-lg flex flex-col items-center justify-center bg-gray-800">
|
||||
<div className="w-full p-8 rounded-lg flex flex-col items-center justify-center">
|
||||
<div className="mx-auto py-auto">
|
||||
<i className="pi pi-lock text-[60px] text-red-500"></i>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user