mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-06 18:31:00 +00:00
Add aothor pubkey as env var, improve login/signup flow
This commit is contained in:
parent
43d0c6d321
commit
6b3991d332
@ -8,7 +8,7 @@ import { Dropdown } from "primereact/dropdown";
|
|||||||
import { v4 as uuidv4, v4 } from 'uuid';
|
import { v4 as uuidv4, v4 } from 'uuid';
|
||||||
import { useLocalStorageWithEffect } from "@/hooks/useLocalStorage";
|
import { useLocalStorageWithEffect } from "@/hooks/useLocalStorage";
|
||||||
import { useNostr } from "@/hooks/useNostr";
|
import { useNostr } from "@/hooks/useNostr";
|
||||||
import {nip19} from "nostr-tools"
|
import { nip19 } from "nostr-tools"
|
||||||
import { parseEvent } from "@/utils/nostr";
|
import { parseEvent } from "@/utils/nostr";
|
||||||
import ContentDropdownItem from "@/components/content/dropdowns/ContentDropdownItem";
|
import ContentDropdownItem from "@/components/content/dropdowns/ContentDropdownItem";
|
||||||
import 'primeicons/primeicons.css';
|
import 'primeicons/primeicons.css';
|
||||||
@ -119,12 +119,12 @@ const CourseForm = () => {
|
|||||||
if (published) {
|
if (published) {
|
||||||
// delete the draft
|
// delete the draft
|
||||||
axios.delete(`/api/drafts/${lesson.id}`)
|
axios.delete(`/api/drafts/${lesson.id}`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
console.log('Draft deleted:', response);
|
console.log('Draft deleted:', response);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Error deleting draft:', error);
|
console.error('Error deleting draft:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,17 +178,22 @@ const CourseForm = () => {
|
|||||||
const signedCourseEvent = await window?.nostr?.signEvent(courseEvent);
|
const signedCourseEvent = await window?.nostr?.signEvent(courseEvent);
|
||||||
console.log('signedCourseEvent:', signedCourseEvent);
|
console.log('signedCourseEvent:', signedCourseEvent);
|
||||||
// Publish the course event using Nostr
|
// Publish the course event using Nostr
|
||||||
await publish(signedCourseEvent);
|
const published = await publish(signedCourseEvent);
|
||||||
|
|
||||||
// Reset the form fields after publishing the course
|
if (published) {
|
||||||
setTitle('');
|
|
||||||
setSummary('');
|
// Reset the form fields after publishing the course
|
||||||
setChecked(false);
|
setTitle('');
|
||||||
setPrice(0);
|
setSummary('');
|
||||||
setCoverImage('');
|
setChecked(false);
|
||||||
setLessons([{ id: uuidv4(), title: 'Select a lesson' }]);
|
setPrice(0);
|
||||||
setSelectedLessons([]);
|
setCoverImage('');
|
||||||
setTopics(['']);
|
setLessons([{ id: uuidv4(), title: 'Select a lesson' }]);
|
||||||
|
setSelectedLessons([]);
|
||||||
|
setTopics(['']);
|
||||||
|
} else {
|
||||||
|
// Handle error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
19
src/db/models/genericModels.js
Normal file
19
src/db/models/genericModels.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import prisma from "../prisma";
|
||||||
|
|
||||||
|
export const getAllContentIds = async () => {
|
||||||
|
const courseIds = await prisma.course.findMany({
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const resourceIds = await prisma.resource.findMany({
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const combinedIds = [...courseIds, ...resourceIds].map((item) => item.id);
|
||||||
|
|
||||||
|
return combinedIds;
|
||||||
|
};
|
@ -1,28 +1,17 @@
|
|||||||
// db/prisma.js
|
const { PrismaClient } = require('@prisma/client');
|
||||||
|
|
||||||
// Import the PrismaClient class from the @prisma/client package.
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
|
|
||||||
// Declare a variable to hold our Prisma client instance.
|
// Declare a variable to hold our Prisma client instance.
|
||||||
let prisma;
|
let prisma;
|
||||||
|
|
||||||
// Check if the application is running in a production environment.
|
// Check if there is already an instance of PrismaClient attached to the global object.
|
||||||
if (process.env.NODE_ENV === 'production') {
|
// If not, create a new instance of PrismaClient and attach it to the global object.
|
||||||
// In production, always create a new instance of PrismaClient.
|
// This ensures that the same instance of PrismaClient is reused across multiple invocations.
|
||||||
prisma = new PrismaClient();
|
if (!global.prisma) {
|
||||||
} else {
|
global.prisma = new PrismaClient();
|
||||||
// In development or other non-production environments...
|
|
||||||
|
|
||||||
// Check if there is already an instance of PrismaClient attached to the global object.
|
|
||||||
if (!global.prisma) {
|
|
||||||
// If not, create a new instance of PrismaClient...
|
|
||||||
global.prisma = new PrismaClient();
|
|
||||||
}
|
|
||||||
// ...and assign it to the prisma variable. This ensures that in development,
|
|
||||||
// the same instance of PrismaClient is reused across hot reloads and server restarts,
|
|
||||||
// which can help prevent the exhaustion of database connections during development.
|
|
||||||
prisma = global.prisma;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assign the global PrismaClient instance to the prisma variable.
|
||||||
|
prisma = global.prisma;
|
||||||
|
|
||||||
// Export the prisma client instance, making it available for import in other parts of the application.
|
// Export the prisma client instance, making it available for import in other parts of the application.
|
||||||
export default prisma;
|
module.exports = prisma;
|
||||||
|
@ -61,42 +61,46 @@ export const useLogin = () => {
|
|||||||
|
|
||||||
const nostrLogin = useCallback(async () => {
|
const nostrLogin = useCallback(async () => {
|
||||||
if (!window || !window.nostr) {
|
if (!window || !window.nostr) {
|
||||||
showToast('error', 'Nostr Unavailable', 'Nostr is not available');
|
showToast('error', 'Nostr Unavailable', 'Nostr is not available');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const publicKey = await window.nostr.getPublicKey();
|
const publicKey = await window.nostr.getPublicKey();
|
||||||
if (!publicKey) {
|
if (!publicKey) {
|
||||||
alert('Failed to obtain public key');
|
showToast('error', 'Public Key Error', 'Failed to obtain public key');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`/api/users/${publicKey}`);
|
const response = await axios.get(`/api/users/${publicKey}`);
|
||||||
if (response.status !== 200) throw new Error('User not found');
|
let userData;
|
||||||
;
|
|
||||||
window.localStorage.setItem('user', JSON.stringify(response.data));
|
if (response.status === 204) {
|
||||||
router.push('/').then(() => window.location.reload());
|
|
||||||
} catch (error) {
|
|
||||||
// User not found, create a new user
|
// User not found, create a new user
|
||||||
const kind0 = await fetchKind0(publicKey);
|
const kind0 = await fetchKind0(publicKey);
|
||||||
const fields = await findKind0Fields(kind0);
|
|
||||||
const payload = { pubkey: publicKey, ...fields };
|
let fields = {};
|
||||||
|
if (kind0) {
|
||||||
try {
|
fields = await findKind0Fields(kind0);
|
||||||
const createUserResponse = await axios.post(`/api/users`, payload);
|
|
||||||
if (createUserResponse.status === 201) {
|
|
||||||
window.localStorage.setItem('user', JSON.stringify(createUserResponse.data));
|
|
||||||
router.push('/').then(() => window.location.reload());
|
|
||||||
} else {
|
|
||||||
console.error('Error creating user:', createUserResponse);
|
|
||||||
}
|
|
||||||
} catch (createError) {
|
|
||||||
console.error('Error creating user:', createError);
|
|
||||||
showToast('error', 'Error Creating User', 'Failed to create user');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const payload = { pubkey: publicKey, ...fields };
|
||||||
|
const createUserResponse = await axios.post(`/api/users`, payload);
|
||||||
|
if (createUserResponse.status !== 201) {
|
||||||
|
throw new Error('Failed to create user');
|
||||||
|
}
|
||||||
|
userData = createUserResponse.data;
|
||||||
|
} else {
|
||||||
|
userData = response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.localStorage.setItem('user', JSON.stringify(userData));
|
||||||
|
router.push('/').then(() => window.location.reload());
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during login:', error);
|
||||||
|
showToast('error', 'Login Error', error.message || 'Failed to log in');
|
||||||
}
|
}
|
||||||
}, [router, showToast, fetchKind0]);
|
}, [router, showToast, fetchKind0]);
|
||||||
|
|
||||||
const anonymousLogin = useCallback(() => {
|
const anonymousLogin = useCallback(() => {
|
||||||
try {
|
try {
|
||||||
|
@ -14,6 +14,8 @@ const defaultRelays = [
|
|||||||
"wss://relay.primal.net/"
|
"wss://relay.primal.net/"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const AUTHOR_PUBKEY = process.env.NEXT_PUBLIC_AUTHOR_PUBKEY;
|
||||||
|
|
||||||
export function useNostr() {
|
export function useNostr() {
|
||||||
const pool = useContext(NostrContext);
|
const pool = useContext(NostrContext);
|
||||||
const subscriptionQueue = useRef([]);
|
const subscriptionQueue = useRef([]);
|
||||||
@ -175,12 +177,12 @@ export function useNostr() {
|
|||||||
aTagsAlt.push(`${event.kind}:${event.pubkey}:${event.d}`);
|
aTagsAlt.push(`${event.kind}:${event.pubkey}:${event.d}`);
|
||||||
eTags.push(event.id);
|
eTags.push(event.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create filters for batch querying
|
// Create filters for batch querying
|
||||||
const filterA = { kinds: [9735], '#a': aTags };
|
const filterA = { kinds: [9735], '#a': aTags };
|
||||||
const filterE = { kinds: [9735], '#e': eTags };
|
const filterE = { kinds: [9735], '#e': eTags };
|
||||||
const filterAAlt = { kinds: [9735], '#a': aTagsAlt };
|
const filterAAlt = { kinds: [9735], '#a': aTagsAlt };
|
||||||
|
|
||||||
// Perform batch queries
|
// Perform batch queries
|
||||||
// const [zapsA, zapsE] = await Promise.all([
|
// const [zapsA, zapsE] = await Promise.all([
|
||||||
// pool.querySync(defaultRelays, filterA),
|
// pool.querySync(defaultRelays, filterA),
|
||||||
@ -212,7 +214,7 @@ export function useNostr() {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
querySyncQueue.current.push(async () => {
|
querySyncQueue.current.push(async () => {
|
||||||
const zaps = await querySyncFn();
|
const zaps = await querySyncFn();
|
||||||
@ -222,32 +224,33 @@ export function useNostr() {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
[pool, processQuerySyncQueue]
|
[pool, processQuerySyncQueue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchKind0 = useCallback(
|
const fetchKind0 = useCallback(
|
||||||
async (publicKey) => {
|
async (publicKey) => {
|
||||||
try {
|
return new Promise((resolve) => {
|
||||||
const kind0 = await new Promise((resolve, reject) => {
|
const timeout = setTimeout(() => {
|
||||||
subscribe(
|
resolve(null); // Resolve with null if no event is received within the timeout
|
||||||
[{ authors: [publicKey], kinds: [0] }],
|
}, 10000); // 10 seconds timeout
|
||||||
{
|
|
||||||
onevent: (event) => {
|
subscribe(
|
||||||
resolve(JSON.parse(event.content));
|
[{ authors: [publicKey], kinds: [0] }],
|
||||||
},
|
{
|
||||||
onerror: (error) => {
|
onevent: (event) => {
|
||||||
reject(error);
|
clearTimeout(timeout);
|
||||||
},
|
resolve(JSON.parse(event.content));
|
||||||
}
|
},
|
||||||
);
|
onerror: (error) => {
|
||||||
});
|
clearTimeout(timeout);
|
||||||
return kind0;
|
console.error('Error fetching kind 0:', error);
|
||||||
} catch (error) {
|
resolve(null);
|
||||||
console.error('Failed to fetch kind 0 for event:', error);
|
},
|
||||||
return [];
|
}
|
||||||
}
|
);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[subscribe]
|
[subscribe]
|
||||||
);
|
);
|
||||||
|
|
||||||
const zapEvent = useCallback(
|
const zapEvent = useCallback(
|
||||||
async (event, amount, comment) => {
|
async (event, amount, comment) => {
|
||||||
@ -334,7 +337,7 @@ export function useNostr() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const fetchResources = useCallback(async () => {
|
const fetchResources = useCallback(async () => {
|
||||||
const filter = [{ kinds: [30023, 30402], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
|
const filter = [{ kinds: [30023, 30402], authors: [AUTHOR_PUBKEY] }];
|
||||||
const hasRequiredTags = (tags) => {
|
const hasRequiredTags = (tags) => {
|
||||||
const hasPlebDevs = tags.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
const hasPlebDevs = tags.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
||||||
// Check if 'resource' tag exists
|
// Check if 'resource' tag exists
|
||||||
@ -374,12 +377,12 @@ export function useNostr() {
|
|||||||
}, [subscribe]);
|
}, [subscribe]);
|
||||||
|
|
||||||
const fetchWorkshops = useCallback(async () => {
|
const fetchWorkshops = useCallback(async () => {
|
||||||
const filter = [{ kinds: [30023, 30402], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
|
const filter = [{ kinds: [30023, 30402], authors: [AUTHOR_PUBKEY] }];
|
||||||
const hasRequiredTags = (tags) => {
|
const hasRequiredTags = (tags) => {
|
||||||
const hasPlebDevs = tags.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
const hasPlebDevs = tags.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
||||||
|
|
||||||
const hasWorkshop = tags.some(([tag, value]) => tag === "t" && value === "workshop");
|
const hasWorkshop = tags.some(([tag, value]) => tag === "t" && value === "workshop");
|
||||||
|
|
||||||
return hasPlebDevs && hasWorkshop;
|
return hasPlebDevs && hasWorkshop;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -414,7 +417,7 @@ export function useNostr() {
|
|||||||
}, [subscribe]);
|
}, [subscribe]);
|
||||||
|
|
||||||
const fetchCourses = useCallback(async () => {
|
const fetchCourses = useCallback(async () => {
|
||||||
const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
|
const filter = [{ kinds: [30023], authors: [AUTHOR_PUBKEY] }];
|
||||||
const hasRequiredTags = (tags) => {
|
const hasRequiredTags = (tags) => {
|
||||||
const hasPlebDevs = tags.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
const hasPlebDevs = tags.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
||||||
|
|
||||||
@ -453,5 +456,94 @@ export function useNostr() {
|
|||||||
});
|
});
|
||||||
}, [subscribe]);
|
}, [subscribe]);
|
||||||
|
|
||||||
return { subscribe, publish, fetchSingleEvent, fetchZapsForEvent, fetchKind0, fetchResources, fetchWorkshops, fetchCourses, zapEvent, fetchZapsForEvents };
|
const publishResource = useCallback(
|
||||||
|
async (resourceEvent) => {
|
||||||
|
const published = await publish(resourceEvent);
|
||||||
|
|
||||||
|
if (published) {
|
||||||
|
const { id, kind, pubkey, content, title, summary, image, published_at, d, topics } = parseEvent(resourceEvent);
|
||||||
|
|
||||||
|
const user = window.localStorage.getItem('user');
|
||||||
|
const userId = JSON.parse(user).id;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payload && payload.user) {
|
||||||
|
try {
|
||||||
|
const response = await axios.post('/api/resources', payload);
|
||||||
|
|
||||||
|
if (response.status === 201) {
|
||||||
|
try {
|
||||||
|
const deleteResponse = await axios.delete(`/api/drafts/${resourceEvent.id}`);
|
||||||
|
|
||||||
|
if (deleteResponse.status === 204) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting draft:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating resource:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
[publish]
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const publishCourse = useCallback(
|
||||||
|
async (courseEvent) => {
|
||||||
|
const published = await publish(courseEvent);
|
||||||
|
|
||||||
|
if (published) {
|
||||||
|
const user = window.localStorage.getItem('user');
|
||||||
|
const pubkey = JSON.parse(user).pubkey;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
title: courseEvent.title,
|
||||||
|
summary: courseEvent.summary,
|
||||||
|
type: 'course',
|
||||||
|
content: courseEvent.content,
|
||||||
|
image: courseEvent.image,
|
||||||
|
user: pubkey,
|
||||||
|
topics: [...courseEvent.topics.map(topic => topic.trim().toLowerCase()), 'plebdevs', 'course']
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payload && payload.user) {
|
||||||
|
try {
|
||||||
|
const response = await axios.post('/api/courses', payload);
|
||||||
|
|
||||||
|
if (response.status === 201) {
|
||||||
|
try {
|
||||||
|
const deleteResponse = await axios.delete(`/api/drafts/${courseEvent.id}`);
|
||||||
|
|
||||||
|
if (deleteResponse.status === 204) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting draft:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating course:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
[publish]
|
||||||
|
);
|
||||||
|
|
||||||
|
return { subscribe, publish, fetchSingleEvent, fetchZapsForEvent, fetchKind0, fetchResources, fetchWorkshops, fetchCourses, zapEvent, fetchZapsForEvents, publishResource, publishCourse };
|
||||||
}
|
}
|
@ -13,6 +13,8 @@ const initialRelays = [
|
|||||||
"wss://relay.primal.net/"
|
"wss://relay.primal.net/"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const AUTHOR_PUBKEY = process.env.NEXT_PUBLIC_AUTHOR_PUBKEY;
|
||||||
|
|
||||||
export const useNostr = () => {
|
export const useNostr = () => {
|
||||||
const [relays, setRelays] = useState(initialRelays);
|
const [relays, setRelays] = useState(initialRelays);
|
||||||
const [relayStatuses, setRelayStatuses] = useState({});
|
const [relayStatuses, setRelayStatuses] = useState({});
|
||||||
@ -159,7 +161,7 @@ export const useNostr = () => {
|
|||||||
|
|
||||||
// Fetch resources, workshops, courses, and streams with appropriate filters and update functions
|
// Fetch resources, workshops, courses, and streams with appropriate filters and update functions
|
||||||
const fetchResources = async () => {
|
const fetchResources = async () => {
|
||||||
const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
|
const filter = [{ kinds: [30023], authors: [AUTHOR_PUBKEY] }];
|
||||||
const hasRequiredTags = async (eventData) => {
|
const hasRequiredTags = async (eventData) => {
|
||||||
const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
||||||
const hasResource = eventData.some(([tag, value]) => tag === "t" && value === "resource");
|
const hasResource = eventData.some(([tag, value]) => tag === "t" && value === "resource");
|
||||||
@ -181,7 +183,7 @@ export const useNostr = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchWorkshops = async () => {
|
const fetchWorkshops = async () => {
|
||||||
const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
|
const filter = [{ kinds: [30023], authors: [AUTHOR_PUBKEY] }];
|
||||||
const hasRequiredTags = async (eventData) => {
|
const hasRequiredTags = async (eventData) => {
|
||||||
const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
||||||
const hasWorkshop = eventData.some(([tag, value]) => tag === "t" && value === "workshop");
|
const hasWorkshop = eventData.some(([tag, value]) => tag === "t" && value === "workshop");
|
||||||
@ -203,7 +205,7 @@ export const useNostr = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchCourses = async () => {
|
const fetchCourses = async () => {
|
||||||
const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
|
const filter = [{ kinds: [30023], authors: [AUTHOR_PUBKEY] }];
|
||||||
const hasRequiredTags = async (eventData) => {
|
const hasRequiredTags = async (eventData) => {
|
||||||
const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
||||||
const hasCourse = eventData.some(([tag, value]) => tag === "t" && value === "course");
|
const hasCourse = eventData.some(([tag, value]) => tag === "t" && value === "course");
|
||||||
@ -226,7 +228,7 @@ export const useNostr = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// const fetchStreams = () => {
|
// const fetchStreams = () => {
|
||||||
// const filter = [{kinds: [30311], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"]}];
|
// const filter = [{kinds: [30311], authors: [AUTHOR_PUBKEY]}];
|
||||||
// const hasRequiredTags = (eventData) => eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
// const hasRequiredTags = (eventData) => eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
||||||
// fetchEvents(filter, 'streams', hasRequiredTags);
|
// fetchEvents(filter, 'streams', hasRequiredTags);
|
||||||
// }
|
// }
|
||||||
|
16
src/pages/api/content/all.js
Normal file
16
src/pages/api/content/all.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { getAllContentIds } from '../../../db/models/genericModels';
|
||||||
|
|
||||||
|
export default async function handler(req, res) {
|
||||||
|
if (req.method === 'GET') {
|
||||||
|
try {
|
||||||
|
const ids = await getAllContentIds();
|
||||||
|
res.status(200).json(ids);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle any other HTTP method
|
||||||
|
res.setHeader('Allow', ['GET', 'POST']);
|
||||||
|
res.status(405).end(`Method ${req.method} Not Allowed`);
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@ import { getUserById, getUserByPubkey, updateUser, deleteUser } from "@/db/model
|
|||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
const { slug } = req.query;
|
const { slug } = req.query;
|
||||||
|
|
||||||
// Determine if slug is a pubkey or an ID
|
// Determine if slug is a pubkey or an ID
|
||||||
const isPubkey = /^[0-9a-fA-F]{64}$/.test(slug);
|
const isPubkey = /^[0-9a-fA-F]{64}$/.test(slug);
|
||||||
|
|
||||||
@ -15,44 +14,46 @@ export default async function handler(req, res) {
|
|||||||
// Assume slug is an ID
|
// Assume slug is an ID
|
||||||
const id = parseInt(slug);
|
const id = parseInt(slug);
|
||||||
if (isNaN(id)) {
|
if (isNaN(id)) {
|
||||||
return res.status(400).json({ error: "Invalid identifier" });
|
res.status(400).json({ error: "Invalid identifier" });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
user = await getUserById(id);
|
user = await getUserById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return res.status(204).end();
|
res.status(204).end();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (req.method) {
|
switch (req.method) {
|
||||||
case 'GET':
|
case 'GET':
|
||||||
return res.status(200).json(user);
|
res.status(200).json(user);
|
||||||
|
break;
|
||||||
case 'PUT':
|
case 'PUT':
|
||||||
if (!isPubkey) {
|
if (!isPubkey) {
|
||||||
// Update operation should be done with an ID, not a pubkey
|
// Update operation should be done with an ID, not a pubkey
|
||||||
const updatedUser = await updateUser(parseInt(slug), req.body);
|
const updatedUser = await updateUser(parseInt(slug), req.body);
|
||||||
return res.status(200).json(updatedUser);
|
res.status(200).json(updatedUser);
|
||||||
} else {
|
} else {
|
||||||
// Handle attempt to update user with pubkey
|
// Handle attempt to update user with pubkey
|
||||||
return res.status(400).json({ error: "Cannot update user with pubkey. Use ID instead." });
|
res.status(400).json({ error: "Cannot update user with pubkey. Use ID instead." });
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'DELETE':
|
case 'DELETE':
|
||||||
if (!isPubkey) {
|
if (!isPubkey) {
|
||||||
// Delete operation should be done with an ID, not a pubkey
|
// Delete operation should be done with an ID, not a pubkey
|
||||||
await deleteUser(parseInt(slug));
|
await deleteUser(parseInt(slug));
|
||||||
return res.status(204).end();
|
res.status(204).end();
|
||||||
} else {
|
} else {
|
||||||
// Handle attempt to delete user with pubkey
|
// Handle attempt to delete user with pubkey
|
||||||
return res.status(400).json({ error: "Cannot delete user with pubkey. Use ID instead." });
|
res.status(400).json({ error: "Cannot delete user with pubkey. Use ID instead." });
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
res.setHeader('Allow', ['GET', 'PUT', 'DELETE']);
|
res.setHeader('Allow', ['GET', 'PUT', 'DELETE']);
|
||||||
return res.status(405).end(`Method ${req.method} Not Allowed`);
|
res.status(405).end(`Method ${req.method} Not Allowed`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(500).json({ error: error.message });
|
res.status(500).json({ error: error.message });
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -32,7 +32,7 @@ export default function Details() {
|
|||||||
|
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
|
|
||||||
const { publish, fetchSingleEvent } = useNostr();
|
const { publishCourse, publishResource, fetchSingleEvent } = useNostr();
|
||||||
|
|
||||||
const [user] = useLocalStorageWithEffect('user', {});
|
const [user] = useLocalStorageWithEffect('user', {});
|
||||||
|
|
||||||
@ -109,18 +109,25 @@ export default function Details() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await publish(signedEvent);
|
let published;
|
||||||
|
|
||||||
// check if the event is published
|
if (type === 'resource' || type === 'workshop') {
|
||||||
const publishedEvent = await fetchSingleEvent(signedEvent.id);
|
published = await publishResource(signedEvent);
|
||||||
|
} else if (type === 'course') {
|
||||||
|
published = await publishCourse(signedEvent);
|
||||||
|
}
|
||||||
|
|
||||||
console.log('publishedEvent:', publishedEvent);
|
if (published) {
|
||||||
|
// check if the event is published
|
||||||
if (publishedEvent) {
|
const publishedEvent = await fetchSingleEvent(signedEvent.id);
|
||||||
// show success message
|
|
||||||
showToast('success', 'Success', `${type} published successfully.`);
|
console.log('publishedEvent:', publishedEvent);
|
||||||
// delete the draft
|
|
||||||
await axios.delete(`/api/drafts/${draft.id}`)
|
if (publishedEvent) {
|
||||||
|
// show success message
|
||||||
|
showToast('success', 'Success', `${type} published successfully.`);
|
||||||
|
// delete the draft
|
||||||
|
await axios.delete(`/api/drafts/${draft.id}`)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.status === 204) {
|
if (res.status === 204) {
|
||||||
showToast('success', 'Success', 'Draft deleted successfully.');
|
showToast('success', 'Success', 'Draft deleted successfully.');
|
||||||
@ -132,6 +139,7 @@ export default function Details() {
|
|||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,30 @@
|
|||||||
import Head from 'next/head'
|
import Head from 'next/head';
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import CoursesCarousel from '@/components/content/carousels/CoursesCarousel'
|
import CoursesCarousel from '@/components/content/carousels/CoursesCarousel';
|
||||||
import WorkshopsCarousel from '@/components/content/carousels/WorkshopsCarousel'
|
import WorkshopsCarousel from '@/components/content/carousels/WorkshopsCarousel';
|
||||||
import HeroBanner from '@/components/banner/HeroBanner';
|
import HeroBanner from '@/components/banner/HeroBanner';
|
||||||
import ResourcesCarousel from '@/components/content/carousels/ResourcesCarousel';
|
import ResourcesCarousel from '@/components/content/carousels/ResourcesCarousel';
|
||||||
|
import { useLocalStorageWithEffect } from '@/hooks/useLocalStorage';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
const [contentIds, setContentIds] = useLocalStorageWithEffect('contentIds', []);
|
||||||
|
|
||||||
|
// this is ready so now we can pass all ids into fetch hooks from loacl storage
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchContentIds = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get('/api/content/all');
|
||||||
|
const ids = response.data;
|
||||||
|
setContentIds(ids);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch content IDs:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchContentIds();
|
||||||
|
}, [setContentIds]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
@ -21,5 +40,5 @@ export default function Home() {
|
|||||||
<ResourcesCarousel />
|
<ResourcesCarousel />
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user