mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-04-19 19:01:19 +00:00
Fixes to content fetching based on correct tags and presence of id in db, fixed forms
This commit is contained in:
parent
a06542c4a3
commit
6eb4edf617
56
src/components/content/carousels/ResourcesCarousel.js
Normal file
56
src/components/content/carousels/ResourcesCarousel.js
Normal file
@ -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 (
|
||||
<>
|
||||
<h2 className="ml-[6%] mt-4">resources</h2>
|
||||
<Carousel value={[...processedResources, ...processedResources]} numVisible={2} itemTemplate={ResourceTemplate} responsiveOptions={responsiveOptions} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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 });
|
||||
|
@ -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 });
|
||||
|
@ -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 });
|
||||
|
@ -27,7 +27,7 @@ const Create = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-fit mx-auto my-8 flex flex-col justify-center">
|
||||
<div className="w-[80vw] max-w-[80vw] mx-auto my-8 flex flex-col justify-center">
|
||||
<h2 className="text-center mb-8">Create a {homeItems[activeIndex].label}</h2>
|
||||
<MenuTab items={homeItems} activeIndex={activeIndex} onTabChange={setActiveIndex} />
|
||||
{renderForm()}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
<HeroBanner />
|
||||
<CoursesCarousel />
|
||||
<WorkshopsCarousel />
|
||||
<ResourcesCarousel />
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user