diff --git a/src/components/content/carousels/ResourcesCarousel.js b/src/components/content/carousels/ResourcesCarousel.js
new file mode 100644
index 0000000..7a07e35
--- /dev/null
+++ b/src/components/content/carousels/ResourcesCarousel.js
@@ -0,0 +1,56 @@
+import React, { useState, useEffect } from 'react';
+import { Carousel } from 'primereact/carousel';
+import { useRouter } from 'next/router';
+import { useNostr } from '@/hooks/useNostr';
+import { useImageProxy } from '@/hooks/useImageProxy';
+import { parseEvent } from '@/utils/nostr';
+import ResourceTemplate from '@/components/content/carousels/templates/ResourceTemplate';
+
+const responsiveOptions = [
+ {
+ breakpoint: '3000px',
+ numVisible: 3,
+ numScroll: 1
+ },
+ {
+ breakpoint: '1462px',
+ numVisible: 2,
+ numScroll: 1
+ },
+ {
+ breakpoint: '575px',
+ numVisible: 1,
+ numScroll: 1
+ }
+];
+
+export default function ResourcesCarousel() {
+ const [processedResources, setProcessedResources] = useState([]);
+ const [resources, setResources] = useState([]);
+ const router = useRouter();
+ const { fetchResources, events } = useNostr();
+ const { returnImageProxy } = useImageProxy();
+
+ useEffect(() => {
+ if (events && events.resources && events.resources.length > 0) {
+ setResources(events.resources);
+ } else {
+ fetchResources();
+ }
+ }, [events]);
+
+ useEffect(() => {
+ const processResources = resources.map(resource => {
+ const { id, content, title, summary, image, published_at } = parseEvent(resource);
+ return { id, content, title, summary, image, published_at };
+ });
+ setProcessedResources(processResources);
+ }, [resources]);
+
+ return (
+ <>
+
resources
+
+ >
+ );
+}
diff --git a/src/components/content/carousels/WorkshopsCarousel.js b/src/components/content/carousels/WorkshopsCarousel.js
index 275514d..11cc4fe 100644
--- a/src/components/content/carousels/WorkshopsCarousel.js
+++ b/src/components/content/carousels/WorkshopsCarousel.js
@@ -26,7 +26,6 @@ const responsiveOptions = [
export default function WorkshopsCarousel() {
const [processedWorkshops, setProcessedWorkshops] = useState([]);
- const [screenWidth, setScreenWidth] = useState(null);
const [workshops, setWorkshops] = useState([]);
const router = useRouter();
const { fetchWorkshops, events } = useNostr();
@@ -40,35 +39,6 @@ export default function WorkshopsCarousel() {
}
}, [events]);
- useEffect(() => {
- // Update the state to the current window width
- setScreenWidth(window.innerWidth);
-
- const handleResize = () => {
- // Update the state to the new window width when it changes
- setScreenWidth(window.innerWidth);
- };
-
- window.addEventListener('resize', handleResize);
-
- // Remove the event listener on cleanup
- return () => window.removeEventListener('resize', handleResize);
- }, []); // The empty array ensures this effect only runs once, similar to componentDidMount
-
-
- const calculateImageDimensions = () => {
- if (screenWidth >= 1200) {
- // Large screens
- return { width: 426, height: 240 };
- } else if (screenWidth >= 768 && screenWidth < 1200) {
- // Medium screens
- return { width: 344, height: 194 };
- } else {
- // Small screens
- return { width: screenWidth - 120, height: (screenWidth - 120) * (9 / 16) };
- }
- };
-
useEffect(() => {
const processWorkshops = workshops.map(workshop => {
const { id, content, title, summary, image, published_at } = parseEvent(workshop);
diff --git a/src/components/forms/CourseForm.js b/src/components/forms/CourseForm.js
index e357adb..b240273 100644
--- a/src/components/forms/CourseForm.js
+++ b/src/components/forms/CourseForm.js
@@ -28,7 +28,7 @@ const CourseForm = () => {
price: checked ? price : null,
content: text,
topics: topics.map(topic => topic.trim().toLowerCase()),
- resources: resources.map(resource => resource.trim())
+ topics: [...topics.map(topic => topic.trim().toLowerCase()), 'plebdevs', 'course']
};
console.log(payload);
diff --git a/src/components/forms/ResourceForm.js b/src/components/forms/ResourceForm.js
index 6889445..fda5a0f 100644
--- a/src/components/forms/ResourceForm.js
+++ b/src/components/forms/ResourceForm.js
@@ -21,7 +21,7 @@ const ResourceForm = () => {
const [price, setPrice] = useState(0);
const [text, setText] = useState('');
const [coverImage, setCoverImage] = useState('');
- const [topics, setTopics] = useState(['']);
+ const [topics, setTopics] = useState([]);
const [user] = useLocalStorageWithEffect('user', {});
@@ -49,7 +49,7 @@ const ResourceForm = () => {
content: text,
image: coverImage,
user: userResponse.data.id,
- topics: topics.map(topic => topic.trim().toLowerCase())
+ topics: [...topics.map(topic => topic.trim().toLowerCase()), 'plebdevs', 'resource']
};
if (payload && payload.user) {
diff --git a/src/components/forms/WorkshopForm.js b/src/components/forms/WorkshopForm.js
index 8ee11e2..3d55969 100644
--- a/src/components/forms/WorkshopForm.js
+++ b/src/components/forms/WorkshopForm.js
@@ -49,7 +49,7 @@ const WorkshopForm = () => {
isPaidResource: checked,
price: checked ? price : null,
embedCode,
- topics: topics.map(topic => topic.trim().toLowerCase()) // Include topics in the payload
+ topics: [...topics.map(topic => topic.trim().toLowerCase()), 'plebdevs', 'workshop']
};
console.log(payload);
diff --git a/src/components/profile/UserContent.js b/src/components/profile/UserContent.js
index 7841cf2..c9327fe 100644
--- a/src/components/profile/UserContent.js
+++ b/src/components/profile/UserContent.js
@@ -33,9 +33,11 @@ const UserContent = () => {
const fetchAllContent = async () => {
try {
+ console.log(user.id)
// Fetch drafts from the database
const draftsResponse = await axios.get(`/api/drafts/all/${user.id}`);
const drafts = draftsResponse.data;
+ console.log('drafts:', drafts);
// Fetch resources, workshops, and courses from Nostr
fetchResources();
diff --git a/src/hooks/useNostr.js b/src/hooks/useNostr.js
index ce84462..7d6280e 100644
--- a/src/hooks/useNostr.js
+++ b/src/hooks/useNostr.js
@@ -1,5 +1,6 @@
import { useState, useEffect, useRef } from "react";
import { SimplePool, nip19, verifyEvent } from "nostr-tools";
+import axios from "axios";
import { useToast } from "./useToast";
const initialRelays = [
@@ -22,7 +23,7 @@ export const useNostr = () => {
streams: []
});
- const {showToast} = useToast();
+ const { showToast } = useToast();
const pool = useRef(new SimplePool({ seenOnEnabled: true }));
const subscriptions = useRef([]);
@@ -51,8 +52,9 @@ export const useNostr = () => {
const fetchEvents = async (filter, updateDataField, hasRequiredTags) => {
try {
const sub = pool.current.subscribeMany(relays, filter, {
- onevent: (event) => {
- if (hasRequiredTags(event.tags)) {
+ onevent: async (event) => {
+ const shouldInclude = await hasRequiredTags(event.tags);
+ if (shouldInclude) {
setEvents(prevData => ({
...prevData,
[updateDataField]: [...prevData[updateDataField], event]
@@ -74,29 +76,78 @@ export const useNostr = () => {
};
// Fetch resources, workshops, courses, and streams with appropriate filters and update functions
- const fetchResources = () => {
- const filter = [{kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"]}];
- const hasRequiredTags = (eventData) => eventData.some(([tag, value]) => tag === "t" && value === "plebdevs") && eventData.some(([tag, value]) => tag === "t" && value === "resource");
+ const fetchResources = async () => {
+ const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
+ const hasRequiredTags = async (eventData) => {
+ const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
+ const hasResource = eventData.some(([tag, value]) => tag === "t" && value === "resource");
+ if (hasPlebDevs && hasResource) {
+ const resourceId = eventData.find(([tag]) => tag === "d")?.[1];
+ if (resourceId) {
+ try {
+ const response = await axios.get(`/api/resources/${resourceId}`);
+ return response.status === 200;
+ } catch (error) {
+ // Handle 404 or other errors gracefully
+ return false;
+ }
+ }
+ }
+ return false;
+ };
fetchEvents(filter, 'resources', hasRequiredTags);
};
- const fetchWorkshops = () => {
- const filter = [{kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"]}];
- const hasRequiredTags = (eventData) => eventData.some(([tag, value]) => tag === "t" && value === "plebdevs") && eventData.some(([tag, value]) => tag === "t" && value === "resource");
+ const fetchWorkshops = async () => {
+ const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
+ const hasRequiredTags = async (eventData) => {
+ const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
+ const hasWorkshop = eventData.some(([tag, value]) => tag === "t" && value === "workshop");
+ if (hasPlebDevs && hasWorkshop) {
+ const workshopId = eventData.find(([tag]) => tag === "d")?.[1];
+ if (workshopId) {
+ try {
+ const response = await axios.get(`/api/resources/${workshopId}`);
+ return response.status === 200;
+ } catch (error) {
+ // Handle 404 or other errors gracefully
+ return false;
+ }
+ }
+ }
+ return false;
+ };
fetchEvents(filter, 'workshops', hasRequiredTags);
- }
+ };
- const fetchCourses = () => {
- const filter = [{kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"]}];
- const hasRequiredTags = (eventData) => eventData.some(([tag, value]) => tag === "t" && value === "plebdevs") && eventData.some(([tag, value]) => tag === "t" && value === "course");
+ const fetchCourses = async () => {
+ const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
+ const hasRequiredTags = async (eventData) => {
+ const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
+ const hasCourse = eventData.some(([tag, value]) => tag === "t" && value === "course");
+ if (hasPlebDevs && hasCourse) {
+ const courseId = eventData.find(([tag]) => tag === "d")?.[1];
+ if (courseId) {
+ // try {
+ // const response = await axios.get(`/api/resources/${courseId}`);
+ // return response.status === 200;
+ // } catch (error) {
+ // // Handle 404 or other errors gracefully
+ // return false;
+ // }
+ return true;
+ }
+ }
+ return false;
+ };
fetchEvents(filter, 'courses', hasRequiredTags);
- }
+ };
- const fetchStreams = () => {
- const filter = [{kinds: [30311], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"]}];
- const hasRequiredTags = (eventData) => eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
- fetchEvents(filter, 'streams', hasRequiredTags);
- }
+ // const fetchStreams = () => {
+ // const filter = [{kinds: [30311], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"]}];
+ // const hasRequiredTags = (eventData) => eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
+ // fetchEvents(filter, 'streams', hasRequiredTags);
+ // }
const fetchKind0 = async (criteria, params) => {
return new Promise((resolve, reject) => {
@@ -150,45 +201,45 @@ export const useNostr = () => {
const wsRelay = new window.WebSocket(relay)
let timer
let isMessageSentSuccessfully = false
-
- function timedout () {
- clearTimeout(timer)
- wsRelay.close()
- reject(new Error(`relay timeout for ${relay}`))
- }
-
- timer = setTimeout(timedout, timeout)
-
- wsRelay.onopen = function () {
- clearTimeout(timer)
- timer = setTimeout(timedout, timeout)
- wsRelay.send(JSON.stringify(['EVENT', signedEvent]))
- }
-
- wsRelay.onmessage = function (msg) {
- const m = JSON.parse(msg.data)
- if (m[0] === 'OK') {
- isMessageSentSuccessfully = true
+
+ function timedout() {
clearTimeout(timer)
wsRelay.close()
- console.log('Successfully sent event to', relay)
- resolve()
- }
+ reject(new Error(`relay timeout for ${relay}`))
}
-
+
+ timer = setTimeout(timedout, timeout)
+
+ wsRelay.onopen = function () {
+ clearTimeout(timer)
+ timer = setTimeout(timedout, timeout)
+ wsRelay.send(JSON.stringify(['EVENT', signedEvent]))
+ }
+
+ wsRelay.onmessage = function (msg) {
+ const m = JSON.parse(msg.data)
+ if (m[0] === 'OK') {
+ isMessageSentSuccessfully = true
+ clearTimeout(timer)
+ wsRelay.close()
+ console.log('Successfully sent event to', relay)
+ resolve()
+ }
+ }
+
wsRelay.onerror = function (error) {
- clearTimeout(timer)
- console.log(error)
- reject(new Error(`relay error: Failed to send to ${relay}`))
- }
-
- wsRelay.onclose = function () {
- clearTimeout(timer)
- if (!isMessageSentSuccessfully) {
+ clearTimeout(timer)
+ console.log(error)
reject(new Error(`relay error: Failed to send to ${relay}`))
- }
}
- })
+
+ wsRelay.onclose = function () {
+ clearTimeout(timer)
+ if (!isMessageSentSuccessfully) {
+ reject(new Error(`relay error: Failed to send to ${relay}`))
+ }
+ }
+ })
};
@@ -214,7 +265,7 @@ export const useNostr = () => {
console.error('Error publishing event:', error);
}
};
-
+
useEffect(() => {
getRelayStatuses(); // Get initial statuses on mount
@@ -236,7 +287,7 @@ export const useNostr = () => {
fetchResources,
fetchCourses,
fetchWorkshops,
- fetchStreams,
+ // fetchStreams,
getRelayStatuses,
events
};
diff --git a/src/pages/api/courses/[slug].js b/src/pages/api/courses/[slug].js
index 8b9669d..b6aa293 100644
--- a/src/pages/api/courses/[slug].js
+++ b/src/pages/api/courses/[slug].js
@@ -1,11 +1,11 @@
import { getCourseById, updateCourse, deleteCourse } from "@/db/models/courseModels";
export default async function handler(req, res) {
- const { id } = req.query;
+ const { slug } = req.query;
if (req.method === 'GET') {
try {
- const course = await getCourseById(parseInt(id));
+ const course = await getCourseById(slug);
if (course) {
res.status(200).json(course);
} else {
@@ -16,14 +16,14 @@ export default async function handler(req, res) {
}
} else if (req.method === 'PUT') {
try {
- const course = await updateCourse(parseInt(id), req.body);
+ const course = await updateCourse(slug, req.body);
res.status(200).json(course);
} catch (error) {
res.status(400).json({ error: error.message });
}
} else if (req.method === 'DELETE') {
try {
- await deleteCourse(parseInt(id));
+ await deleteCourse(slug);
res.status(204).end();
} catch (error) {
res.status(500).json({ error: error.message });
diff --git a/src/pages/api/drafts/all/[slug].js b/src/pages/api/drafts/all/[slug].js
index 8be5921..fab2c85 100644
--- a/src/pages/api/drafts/all/[slug].js
+++ b/src/pages/api/drafts/all/[slug].js
@@ -1,15 +1,15 @@
import { getAllDraftsByUserId } from "@/db/models/draftModels";
export default async function handler(req, res) {
-const { id } = req.query;
+const { slug } = req.query;
if (req.method === 'GET') {
try {
- const resource = await getAllDraftsByUserId(id);
- if (resource) {
- res.status(200).json(resource);
+ const drafts = await getAllDraftsByUserId(slug);
+ if (drafts) {
+ res.status(200).json(drafts);
} else {
- res.status(404).json({ error: 'Resource not found' });
+ res.status(404).json({ error: 'Drafts not found' });
}
} catch (error) {
res.status(400).json({ error: error.message });
diff --git a/src/pages/api/resources/[slug].js b/src/pages/api/resources/[slug].js
index e0c26b5..e8f4d66 100644
--- a/src/pages/api/resources/[slug].js
+++ b/src/pages/api/resources/[slug].js
@@ -1,11 +1,11 @@
import { getResourceById, updateResource, deleteResource } from "@/db/models/resourceModels";
export default async function handler(req, res) {
- const { id } = req.query;
+ const { slug } = req.query;
if (req.method === 'GET') {
try {
- const resource = await getResourceById(parseInt(id));
+ const resource = await getResourceById(slug);
if (resource) {
res.status(200).json(resource);
} else {
@@ -16,14 +16,14 @@ export default async function handler(req, res) {
}
} else if (req.method === 'PUT') {
try {
- const resource = await updateResource(parseInt(id), req.body);
+ const resource = await updateResource(slug, req.body);
res.status(200).json(resource);
} catch (error) {
res.status(400).json({ error: error.message });
}
} else if (req.method === 'DELETE') {
try {
- await deleteResource(parseInt(id));
+ await deleteResource(slug);
res.status(204).end();
} catch (error) {
res.status(500).json({ error: error.message });
diff --git a/src/pages/create.js b/src/pages/create.js
index bd79f94..60712e6 100644
--- a/src/pages/create.js
+++ b/src/pages/create.js
@@ -27,7 +27,7 @@ const Create = () => {
};
return (
-
+
Create a {homeItems[activeIndex].label}
{renderForm()}
diff --git a/src/pages/details/[slug].js b/src/pages/details/[slug].js
index d083a91..26e2a33 100644
--- a/src/pages/details/[slug].js
+++ b/src/pages/details/[slug].js
@@ -50,7 +50,6 @@ export default function Details() {
const fetchAuthor = async (pubkey) => {
const author = await fetchKind0([{ authors: [pubkey], kinds: [0] }], {});
const fields = await findKind0Fields(author);
- console.log('fields:', fields);
if (fields) {
setAuthor(fields);
}
diff --git a/src/pages/index.js b/src/pages/index.js
index 2a74729..782ed73 100644
--- a/src/pages/index.js
+++ b/src/pages/index.js
@@ -3,6 +3,7 @@ import React from 'react';
import CoursesCarousel from '@/components/content/carousels/CoursesCarousel'
import WorkshopsCarousel from '@/components/content/carousels/WorkshopsCarousel'
import HeroBanner from '@/components/banner/HeroBanner';
+import ResourcesCarousel from '@/components/content/carousels/ResourcesCarousel';
export default function Home() {
return (
@@ -17,6 +18,7 @@ export default function Home() {
+
>
)