From 0ab56b009ce73986905c8e9eb9f35e770090e62b Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sat, 16 Mar 2024 16:37:47 -0500 Subject: [PATCH] improvements to details page ui --- src/hooks/useNostr.js | 55 +++++++++++++++++- src/pages/details/[slug].js | 90 +++++++++++++++++++++++------ src/redux/reducers/eventsReducer.js | 10 +++- src/styles/globals.css | 3 + src/utils/nostr.js | 13 ++++- 5 files changed, 149 insertions(+), 22 deletions(-) diff --git a/src/hooks/useNostr.js b/src/hooks/useNostr.js index df9ae05..8504447 100644 --- a/src/hooks/useNostr.js +++ b/src/hooks/useNostr.js @@ -1,7 +1,7 @@ import { useState, useEffect, useRef } from "react"; import { SimplePool, relayInit, nip19 } from "nostr-tools"; import { useDispatch } from "react-redux"; -import { addResource, addCourse } from "@/redux/reducers/eventsReducer"; +import { addResource, addCourse, addWorkshop, addStream } from "@/redux/reducers/eventsReducer"; import { initialRelays } from "@/redux/reducers/userReducer"; export const useNostr = () => { @@ -88,6 +88,32 @@ export const useNostr = () => { }); } + const fetchWorkshops = async () => { + const filter = [{kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"]}]; + + const params = {seenOnEnabled: true}; + + const hasRequiredTags = (eventData) => { + return eventData.some(([tag, value]) => tag === "t" && value === "plebdevs") && eventData.some(([tag, value]) => tag === "t" && value === "workshop"); + }; + + const sub = pool.current.subscribeMany(relays, filter, { + ...params, + onevent: (event) => { + if (hasRequiredTags(event.tags)) { + dispatch(addWorkshop(event)); + } + }, + onerror: (error) => { + console.error("Error fetching workshops:", error); + }, + oneose: () => { + console.log("Subscription closed"); + sub.close(); + } + }); + } + const fetchCourses = async () => { const filter = [{kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"]}]; @@ -114,6 +140,32 @@ export const useNostr = () => { }); } + const fetchStreams = async () => { + const filter = [{kinds: [30311], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"]}]; + + const params = {seenOnEnabled: true}; + + const hasRequiredTags = (eventData) => { + return eventData.some(([tag, value]) => tag === "t" && value === "plebdevs"); + }; + + const sub = pool.current.subscribeMany(relays, filter, { + ...params, + onevent: (event) => { + if (hasRequiredTags(event.tags)) { + dispatch(addStream(event)); + } + }, + onerror: (error) => { + console.error("Error fetching streams:", error); + }, + oneose: () => { + console.log("Subscription closed"); + sub.close(); + } + }); + } + const fetchSingleEvent = async (id) => { return new Promise((resolve, reject) => { const sub = pool.current.subscribeMany(relays, [{ ids: [id] }], { @@ -159,6 +211,7 @@ export const useNostr = () => { fetchKind0, fetchResources, fetchCourses, + fetchWorkshops, getRelayStatuses, }; }; \ No newline at end of file diff --git a/src/pages/details/[slug].js b/src/pages/details/[slug].js index 075bb07..37415f8 100644 --- a/src/pages/details/[slug].js +++ b/src/pages/details/[slug].js @@ -1,17 +1,20 @@ import React, { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; import { useNostr } from '@/hooks/useNostr'; -import { parseEvent } from '@/utils/nostr'; +import { parseEvent, findKind0Fields, hexToNpub } from '@/utils/nostr'; import { useImageProxy } from '@/hooks/useImageProxy'; +import { Button } from 'primereact/button'; +import { Tag } from 'primereact/tag'; import Image from 'next/image'; import 'primeicons/primeicons.css'; export default function Details() { const [event, setEvent] = useState(null); const [processedEvent, setProcessedEvent] = useState({}); + const [author, setAuthor] = useState(null); const { returnImageProxy } = useImageProxy(); - const { fetchSingleEvent } = useNostr(); + const { fetchSingleEvent, fetchKind0 } = useNostr(); const router = useRouter(); @@ -31,31 +34,80 @@ export default function Details() { }, [router.isReady, router.query]); useEffect(() => { + 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); + } + } if (event) { - const { id, content, title, summary, image, published_at } = parseEvent(event); - setProcessedEvent({ id, content, title, summary, image, published_at }); + fetchAuthor(event.pubkey); + } + }, [event]); + + useEffect(() => { + if (event) { + const { id, pubkey, content, title, summary, image, published_at } = parseEvent(event); + setProcessedEvent({ id, pubkey, content, title, summary, image, published_at }); } }, [event]); return (
router.push('/')} /> +
+
+ + + + + +
+

{processedEvent?.title}

+

{processedEvent?.summary}

+
+ resource thumbnail +

+ Created by{' '} + + {author?.username} + +

+
+
- { - processedEvent && ( - <> - resource thumbnail -

{processedEvent.title}

-

{processedEvent.summary}

- - ) - } + {processedEvent && ( +
+ resource thumbnail +
+ )}
); diff --git a/src/redux/reducers/eventsReducer.js b/src/redux/reducers/eventsReducer.js index 94d0874..84d9618 100644 --- a/src/redux/reducers/eventsReducer.js +++ b/src/redux/reducers/eventsReducer.js @@ -23,6 +23,8 @@ export const eventsSlice = createSlice({ initialState: { resources: [], courses: [], + workshops: [], + streams: [], }, reducers: { addResource: (state, action) => { @@ -31,6 +33,12 @@ export const eventsSlice = createSlice({ addCourse: (state, action) => { addItems(state, action, 'courses'); }, + addWorkshop: (state, action) => { + addItems(state, action, 'workshops'); + }, + addStream: (state, action) => { + addItems(state, action, 'streams'); + }, setResources: (state, action) => { state.resources = action.payload; }, @@ -40,5 +48,5 @@ export const eventsSlice = createSlice({ }, }); -export const { addResource, addCourse, setResources, setCourses } = eventsSlice.actions; +export const { addResource, addCourse, setResources, setCourses, addWorkshop, addStream } = eventsSlice.actions; export default eventsSlice.reducer; diff --git a/src/styles/globals.css b/src/styles/globals.css index 40901c9..baf2443 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -23,3 +23,6 @@ display: none !important; } +.p-button .pi.pi-bolt { + color: yellow; +} diff --git a/src/utils/nostr.js b/src/utils/nostr.js index 2809a82..c885425 100644 --- a/src/utils/nostr.js +++ b/src/utils/nostr.js @@ -1,3 +1,5 @@ +import { nip19 } from "nostr-tools"; + export const findKind0Fields = async (kind0) => { let fields = {} @@ -31,6 +33,7 @@ export const parseEvent = (event) => { // Initialize an object to store the extracted data const eventData = { id: event.id, + pubkey: event.pubkey || '', content: event.content || '', title: '', summary: '', @@ -53,9 +56,17 @@ export const parseEvent = (event) => { case 'published_at': eventData.published_at = tag[1]; break; - // Add cases for any other data you need to extract + case 'author': + eventData.author = tag[1]; + break; + default: + break; } }); return eventData; }; + +export const hexToNpub = (hex) => { + return nip19.npubEncode(hex); +}