mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-04-19 19:01:19 +00:00
Update ndk context to not initiate signer, add purchasedListItem for /profile data table
This commit is contained in:
parent
b937dd2507
commit
5a882bc06b
@ -38,7 +38,7 @@ export default function CourseDetails({ processedEvent }) {
|
||||
const { returnImageProxy } = useImageProxy();
|
||||
const { data: session, status } = useSession();
|
||||
const router = useRouter();
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
|
||||
useEffect(() => {
|
||||
if (session) {
|
||||
|
@ -29,7 +29,7 @@ export default function DraftCourseDetails({ processedEvent, lessons }) {
|
||||
const { returnImageProxy } = useImageProxy();
|
||||
const { data: session, status } = useSession();
|
||||
const router = useRouter();
|
||||
const ndk = useNDKContext();
|
||||
const { ndk, addSigner } = useNDKContext();
|
||||
|
||||
const fetchAuthor = useCallback(async (pubkey) => {
|
||||
if (!pubkey) return;
|
||||
@ -64,6 +64,10 @@ export default function DraftCourseDetails({ processedEvent, lessons }) {
|
||||
const processedLessons = [];
|
||||
|
||||
try {
|
||||
// Step 0: Add signer if not already added
|
||||
if (!ndk.signer) {
|
||||
await addSigner();
|
||||
}
|
||||
// Step 1: Process lessons
|
||||
for (const lesson of lessons) {
|
||||
processedLessons.push({
|
||||
|
@ -34,7 +34,7 @@ const CourseForm = () => {
|
||||
const { drafts, draftsLoading, draftsError } = useDraftsQuery();
|
||||
const { data: session, status } = useSession();
|
||||
const [user, setUser] = useState(null);
|
||||
const ndk = useNDKContext();
|
||||
const { ndk, addSigner } = useNDKContext();
|
||||
const router = useRouter();
|
||||
const { showToast } = useToast();
|
||||
|
||||
@ -51,6 +51,10 @@ const CourseForm = () => {
|
||||
const handleDraftSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!ndk.signer) {
|
||||
await addSigner();
|
||||
}
|
||||
|
||||
// Prepare the lessons from selected lessons
|
||||
const resources = await Promise.all(selectedLessons.map(async (lesson) => {
|
||||
// if .type is present than this lesson is a draft we need to publish
|
||||
|
@ -31,7 +31,7 @@ const ResourceForm = ({ draft = null, isPublished = false }) => {
|
||||
const { data: session, status } = useSession();
|
||||
const { showToast } = useToast();
|
||||
const router = useRouter();
|
||||
const ndk = useNDKContext();
|
||||
const { ndk, addSigner } = useNDKContext();
|
||||
|
||||
useEffect(() => {
|
||||
console.log('isPublished', isPublished);
|
||||
@ -108,6 +108,10 @@ const ResourceForm = ({ draft = null, isPublished = false }) => {
|
||||
console.log('event', event);
|
||||
|
||||
try {
|
||||
if (!ndk.signer) {
|
||||
await addSigner();
|
||||
}
|
||||
|
||||
await ndk.connect();
|
||||
|
||||
const published = await ndk.publish(event);
|
||||
|
@ -73,7 +73,7 @@ const Navbar = () => {
|
||||
onClick={(e) => menu.current.toggle(e)}></i>
|
||||
<Menu model={menuItems} popup ref={menu} />
|
||||
</div> */}
|
||||
<div onClick={() => router.push('/')} className="flex flex-row items-center justify-center cursor-pointer">
|
||||
<div onClick={() => router.push('/').then(() => window.location.reload())} className="flex flex-row items-center justify-center cursor-pointer">
|
||||
<Image
|
||||
alt="logo"
|
||||
src="/plebdevs-guy.jpg"
|
||||
|
@ -28,8 +28,8 @@ const UserAvatar = () => {
|
||||
|
||||
const menu = useRef(null);
|
||||
|
||||
const handleLogout = () => {
|
||||
signOut();
|
||||
const handleLogout = async () => {
|
||||
await signOut({ redirect: false }); // Wait for the sign-out to complete
|
||||
router.push('/').then(() => window.location.reload());
|
||||
}
|
||||
|
||||
|
30
src/components/profile/PurchasedListItem.js
Normal file
30
src/components/profile/PurchasedListItem.js
Normal file
@ -0,0 +1,30 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useNDKContext } from "@/context/NDKContext";
|
||||
import { parseEvent } from "@/utils/nostr";
|
||||
import { ProgressSpinner } from "primereact/progressspinner";
|
||||
|
||||
const PurchasedListItem = ({ eventId, category }) => {
|
||||
const { ndk } = useNDKContext();
|
||||
const [event, setEvent] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchEvent = async () => {
|
||||
if (!eventId) return;
|
||||
|
||||
try {
|
||||
await ndk.connect();
|
||||
const event = await ndk.fetchEvent(eventId);
|
||||
if (event) {
|
||||
setEvent(parseEvent(event));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching event:", error);
|
||||
}
|
||||
}
|
||||
fetchEvent();
|
||||
}, [eventId, ndk]);
|
||||
|
||||
return !event || !ndk ? <ProgressSpinner className="w-[40px] h-[40px]" /> : (<a className="text-blue-500 underline hover:text-blue-600" href={category === "courses" ? `/courses/${event.id}` : `/details/${event.id}`}>{event.title}</a>);
|
||||
}
|
||||
|
||||
export default PurchasedListItem;
|
@ -25,7 +25,7 @@ const UserContent = () => {
|
||||
const [user, setUser] = useState(null);
|
||||
const router = useRouter();
|
||||
const { showToast } = useToast();
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
const { courses, coursesLoading, coursesError } = useCoursesQuery();
|
||||
const { resources, resourcesLoading, resourcesError } = useResourcesQuery();
|
||||
const { workshops, workshopsLoading, workshopsError } = useWorkshopsQuery();
|
||||
|
@ -19,8 +19,8 @@ const ZapDisplay = ({ zapAmount, event, zapsLoading }) => {
|
||||
return (
|
||||
<>
|
||||
<span className="text-xs cursor-pointer flex items-center relative hover:opacity-80" onClick={(e) => op.current.toggle(e)}>
|
||||
<i className="pi pi-bolt text-yellow-300"></i>
|
||||
<span className="relative flex items-center min-w-[20px] min-h-[20px]">
|
||||
<i className="pi pi-bolt text-yellow-300 text-lg"></i>
|
||||
<span className="relative flex items-center min-w-[20px] min-h-[20px] text-sm">
|
||||
{zapsLoading || zapAmount === null || extraLoading ? (
|
||||
<ProgressSpinner className="absolute top-0 left-0 w-[20px] h-[20px]" strokeWidth="8" animationDuration=".5s" />
|
||||
) : (
|
||||
|
@ -4,31 +4,38 @@ import NDK, { NDKNip07Signer } from "@nostr-dev-kit/ndk";
|
||||
const NDKContext = createContext(null);
|
||||
|
||||
const relayUrls = [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.snort.social/",
|
||||
"wss://relay.nostr.band/",
|
||||
"wss://nostr.mutinywallet.com/",
|
||||
"wss://relay.mutinywallet.com/",
|
||||
"wss://relay.primal.net/"
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.snort.social/",
|
||||
"wss://relay.nostr.band/",
|
||||
"wss://nostr.mutinywallet.com/",
|
||||
"wss://relay.mutinywallet.com/",
|
||||
"wss://relay.primal.net/"
|
||||
];
|
||||
|
||||
export const NDKProvider = ({ children }) => {
|
||||
const [ndk, setNdk] = useState(null);
|
||||
const [ndk, setNdk] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const nip07signer = new NDKNip07Signer();
|
||||
const instance = new NDK({ explicitRelayUrls: relayUrls, signer: nip07signer });
|
||||
setNdk(instance);
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
const instance = new NDK({ explicitRelayUrls: relayUrls });
|
||||
setNdk(instance);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<NDKContext.Provider value={ndk}>
|
||||
{children}
|
||||
</NDKContext.Provider>
|
||||
);
|
||||
const addSigner = async () => {
|
||||
if (ndk) {
|
||||
const nip07signer = new NDKNip07Signer();
|
||||
await ndk.signer?.user();
|
||||
ndk.signer = nip07signer;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<NDKContext.Provider value={{ ndk, addSigner }}>
|
||||
{children}
|
||||
</NDKContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useNDKContext = () => {
|
||||
return useContext(NDKContext);
|
||||
};
|
||||
return useContext(NDKContext);
|
||||
};
|
@ -4,7 +4,7 @@ import { useNDKContext } from '@/context/NDKContext';
|
||||
|
||||
export function useAllContentQuery({ids}) {
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true);
|
||||
|
@ -7,7 +7,7 @@ const AUTHOR_PUBKEY = process.env.NEXT_PUBLIC_AUTHOR_PUBKEY;
|
||||
|
||||
export function useCoursesQuery() {
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true);
|
||||
|
@ -7,7 +7,7 @@ const AUTHOR_PUBKEY = process.env.NEXT_PUBLIC_AUTHOR_PUBKEY;
|
||||
|
||||
export function useResourcesQuery() {
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true);
|
||||
|
@ -7,7 +7,7 @@ const AUTHOR_PUBKEY = process.env.NEXT_PUBLIC_AUTHOR_PUBKEY;
|
||||
|
||||
export function useWorkshopsQuery() {
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true);
|
||||
|
@ -4,7 +4,7 @@ import { useNDKContext } from '@/context/NDKContext';
|
||||
|
||||
export function useZapsQuery({ event, type }) {
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true);
|
||||
|
@ -5,7 +5,7 @@ export function useZapsSubscription({event}) {
|
||||
const [zaps, setZaps] = useState([]);
|
||||
const [zapsLoading, setZapsLoading] = useState(true);
|
||||
const [zapsError, setZapsError] = useState(null);
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
|
||||
useEffect(() => {
|
||||
let subscription;
|
||||
@ -19,12 +19,9 @@ export function useZapsSubscription({event}) {
|
||||
{ kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }
|
||||
];
|
||||
await ndk.connect();
|
||||
console.log("filters", filters);
|
||||
subscription = ndk.subscribe(filters);
|
||||
|
||||
subscription.on('event', (zapEvent) => {
|
||||
console.log("event", zapEvent);
|
||||
|
||||
subscription.on('event', (zapEvent) => {
|
||||
// Check if we've already seen this zap
|
||||
if (!zapIds.has(zapEvent.id)) {
|
||||
zapIds.add(zapEvent.id);
|
||||
|
@ -75,6 +75,7 @@ export default NextAuth({
|
||||
],
|
||||
callbacks: {
|
||||
async jwt({ token, trigger, user }) {
|
||||
console.log('TRIGGER', trigger);
|
||||
if (trigger === "update") {
|
||||
// if we trigger an update call the authorize function again
|
||||
const newUser = await authorize(token.user.pubkey);
|
||||
@ -95,6 +96,12 @@ export default NextAuth({
|
||||
async redirect({ url, baseUrl }) {
|
||||
return baseUrl;
|
||||
},
|
||||
async signOut({ token, session }) {
|
||||
console.log('signOut', token, session);
|
||||
token = {}
|
||||
session = {}
|
||||
return true
|
||||
},
|
||||
},
|
||||
secret: process.env.NEXTAUTH_SECRET,
|
||||
session: { strategy: "jwt" },
|
||||
|
@ -2,13 +2,14 @@ import { signIn, useSession } from "next-auth/react"
|
||||
import { useState, useEffect } from "react"
|
||||
import { useNDKContext } from "@/context/NDKContext";
|
||||
import { Button } from 'primereact/button';
|
||||
import NDK, { NDKEvent, NDKNip07Signer } from "@nostr-dev-kit/ndk";
|
||||
|
||||
export default function SignIn() {
|
||||
const [email, setEmail] = useState("")
|
||||
const [nostrPubkey, setNostrPubkey] = useState("")
|
||||
const [nostrPrivkey, setNostrPrivkey] = useState("")
|
||||
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
|
||||
const { data: session, status } = useSession(); // Get the current session's data and status
|
||||
|
||||
useEffect(() => {
|
||||
@ -22,14 +23,14 @@ export default function SignIn() {
|
||||
|
||||
const handleNostrSignIn = async (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
const nip07signer = new NDKNip07Signer();
|
||||
const ndk = new NDK({ signer: nip07signer });
|
||||
|
||||
await ndk.connect()
|
||||
if (!ndk.signer) {
|
||||
await addSigner();
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const user = await nip07signer.user()
|
||||
const user = await ndk.signer.user()
|
||||
|
||||
const pubkey = user?._pubkey
|
||||
signIn("nostr", { pubkey })
|
||||
|
@ -20,7 +20,7 @@ const DraftCourse = () => {
|
||||
const [lessonsWithAuthors, setLessonsWithAuthors] = useState([]);
|
||||
|
||||
const router = useRouter();
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
|
||||
const fetchAuthor = useCallback(async (pubkey) => {
|
||||
if (!pubkey) return;
|
||||
|
@ -19,7 +19,7 @@ const Course = () => {
|
||||
const [lessons, setLessons] = useState([]);
|
||||
|
||||
const router = useRouter();
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
|
||||
const fetchAuthor = useCallback(async (pubkey) => {
|
||||
const author = await ndk.getUser({ pubkey });
|
||||
|
@ -10,7 +10,7 @@ import { useToast } from "@/hooks/useToast";
|
||||
export default function Edit() {
|
||||
const [event, setEvent] = useState(null);
|
||||
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
const router = useRouter();
|
||||
const { showToast } = useToast();
|
||||
|
||||
|
@ -31,7 +31,7 @@ export default function Details() {
|
||||
const [decryptedContent, setDecryptedContent] = useState(null);
|
||||
const [authorView, setAuthorView] = useState(false);
|
||||
|
||||
const ndk = useNDKContext();
|
||||
const {ndk, addSigner} = useNDKContext();
|
||||
const { data: session, update } = useSession();
|
||||
const [user, setUser] = useState(null);
|
||||
const { showToast } = useToast();
|
||||
|
@ -49,7 +49,7 @@ export default function Draft() {
|
||||
const { width, height } = useResponsiveImageDimensions();
|
||||
const router = useRouter();
|
||||
const { showToast } = useToast();
|
||||
const ndk = useNDKContext();
|
||||
const { ndk, addSigner } = useNDKContext();
|
||||
|
||||
useEffect(() => {
|
||||
if (session) {
|
||||
@ -74,6 +74,10 @@ export default function Draft() {
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
if (!ndk.signer) {
|
||||
await addSigner();
|
||||
}
|
||||
|
||||
if (draft) {
|
||||
const { unsignedEvent, type } = await buildEvent(draft);
|
||||
|
||||
|
@ -5,6 +5,10 @@ import { Menu } from "primereact/menu";
|
||||
import { Column } from "primereact/column";
|
||||
import { useImageProxy } from "@/hooks/useImageProxy";
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { ProgressSpinner } from "primereact/progressspinner";
|
||||
import PurchasedListItem from "@/components/profile/PurchasedListItem";
|
||||
import { useNDKContext } from "@/context/NDKContext";
|
||||
import { formatDateTime } from "@/utils/time";
|
||||
import UserContent from "@/components/profile/UserContent";
|
||||
import Image from "next/image";
|
||||
import BitcoinConnectButton from "@/components/bitcoinConnect/BitcoinConnect";
|
||||
@ -15,6 +19,7 @@ const Profile = () => {
|
||||
|
||||
const { data: session, status } = useSession();
|
||||
const { returnImageProxy } = useImageProxy();
|
||||
const { ndk } = useNDKContext();
|
||||
const menu = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
@ -33,8 +38,6 @@ const Profile = () => {
|
||||
}
|
||||
}, [session]);
|
||||
|
||||
const purchases = [];
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
label: "Edit",
|
||||
@ -96,17 +99,28 @@ const Profile = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DataTable
|
||||
emptyMessage="No purchases"
|
||||
value={purchases}
|
||||
tableStyle={{ minWidth: "100%" }}
|
||||
header={header}
|
||||
>
|
||||
<Column field="cost" header="Cost"></Column>
|
||||
<Column field="name" header="Name"></Column>
|
||||
<Column field="category" header="Category"></Column>
|
||||
<Column field="date" header="Date"></Column>
|
||||
</DataTable>
|
||||
{!session || !session?.user || !ndk ? (
|
||||
<ProgressSpinner />
|
||||
) : (
|
||||
<DataTable
|
||||
emptyMessage="No purchases"
|
||||
value={session.user?.purchased}
|
||||
tableStyle={{ minWidth: "100%" }}
|
||||
header={header}
|
||||
>
|
||||
<Column field="amountPaid" header="Cost"></Column>
|
||||
<Column
|
||||
body={(rowData) => {
|
||||
console.log("rowData", rowData);
|
||||
return <PurchasedListItem eventId={rowData?.resource?.noteId || rowData?.course?.noteId} category={rowData?.course ? "courses" : "resources"} />
|
||||
}}
|
||||
header="Name"
|
||||
></Column>
|
||||
<Column body={session.user?.purchased?.some((item) => item.courseId) ? "course" : "resource"} header="Category"></Column>
|
||||
<Column body={rowData => formatDateTime(rowData?.createdAt)} header="Date"></Column>
|
||||
</DataTable>
|
||||
|
||||
)}
|
||||
<UserContent />
|
||||
</div>
|
||||
)
|
||||
|
@ -3,6 +3,24 @@ export const formatUnixTimestamp = (time) => {
|
||||
return date.toDateString();
|
||||
}
|
||||
|
||||
export const formatDateTime = (isoDate) => {
|
||||
const date = new Date(isoDate);
|
||||
|
||||
// Example: Format to a more readable string
|
||||
const formattedDate = date.toLocaleString("en-US", {
|
||||
timeZone: "UTC", // Optional: You can change this to the user's time zone if needed
|
||||
weekday: "long", // "long" for full name, "short" for abbreviated
|
||||
year: "numeric",
|
||||
month: "long", // "long" for full name, "short" for abbreviated
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
second: "numeric",
|
||||
});
|
||||
|
||||
return formattedDate;
|
||||
}
|
||||
|
||||
export const formatTimestampToHowLongAgo = (time) => {
|
||||
const date = new Date(time * 1000);
|
||||
const now = new Date();
|
||||
|
Loading…
x
Reference in New Issue
Block a user