mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-04-19 19:01:19 +00:00
improvements to details page ui
This commit is contained in:
parent
be6bb02db0
commit
0ab56b009c
@ -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,
|
||||
};
|
||||
};
|
@ -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 (
|
||||
<div className='flex flex-row justify-between m-4'>
|
||||
<i className='pi pi-arrow-left cursor-pointer hover:opacity-75' onClick={() => router.push('/')} />
|
||||
<div className='flex flex-col items-start'>
|
||||
<div className='flex flex-row justify-start w-full'>
|
||||
<Tag className='mr-2' value="Primary"></Tag>
|
||||
<Tag className='mr-2' severity="success" value="Success"></Tag>
|
||||
<Tag className='mr-2' severity="info" value="Info"></Tag>
|
||||
<Tag className='mr-2' severity="warning" value="Warning"></Tag>
|
||||
<Tag className='mr-2' severity="danger" value="Danger"></Tag>
|
||||
</div>
|
||||
<h1 className='text-4xl mt-6'>{processedEvent?.title}</h1>
|
||||
<p className='text-xl mt-6'>{processedEvent?.summary}</p>
|
||||
<div className='flex flex-row w-full mt-6 items-center'>
|
||||
<Image
|
||||
alt="resource thumbnail"
|
||||
src={returnImageProxy(author?.avatar)}
|
||||
width={50}
|
||||
height={50}
|
||||
className="rounded-full mr-4"
|
||||
/>
|
||||
<p className='text-lg'>
|
||||
Created by{' '}
|
||||
<a rel='noreferrer noopener' target='_blank' className='text-blue-500 hover:underline'>
|
||||
{author?.username}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
{
|
||||
processedEvent && (
|
||||
<>
|
||||
<Image
|
||||
alt="resource thumbnail"
|
||||
src={returnImageProxy(processedEvent.image)}
|
||||
width={344}
|
||||
height={194}
|
||||
className="w-full h-full object-cover object-center rounded-lg"
|
||||
/>
|
||||
<h2>{processedEvent.title}</h2>
|
||||
<p>{processedEvent.summary}</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{processedEvent && (
|
||||
<div className='flex flex-col items-center justify-between rounded-lg h-72 p-4 bg-gray-700 drop-shadow-md'>
|
||||
<Image
|
||||
alt="resource thumbnail"
|
||||
src={returnImageProxy(processedEvent.image)}
|
||||
width={344}
|
||||
height={194}
|
||||
className="object-cover object-center rounded-lg"
|
||||
/>
|
||||
<Button
|
||||
icon="pi pi-bolt"
|
||||
label="100 sats"
|
||||
severity="success"
|
||||
outlined
|
||||
pt={{
|
||||
button: {
|
||||
icon: ({ context }) => ({
|
||||
className: 'bg-yellow-500'
|
||||
})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -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;
|
||||
|
@ -23,3 +23,6 @@
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.p-button .pi.pi-bolt {
|
||||
color: yellow;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user