diff --git a/src/components/forms/ResourceForm.js b/src/components/forms/ResourceForm.js
index fda5a0f..83218b5 100644
--- a/src/components/forms/ResourceForm.js
+++ b/src/components/forms/ResourceForm.js
@@ -1,46 +1,53 @@
-import React, { use, useState } from "react";
+import React, { useState, useEffect } from "react";
import axios from "axios";
import { InputText } from "primereact/inputtext";
import { InputNumber } from "primereact/inputnumber";
import { InputSwitch } from "primereact/inputswitch";
import { Editor } from "primereact/editor";
import { Button } from "primereact/button";
-import { nip04, verifyEvent, nip19 } from "nostr-tools";
import { useRouter } from "next/router";
import { useNostr } from "@/hooks/useNostr";
-import { v4 as uuidv4 } from 'uuid';
import { useLocalStorageWithEffect } from "@/hooks/useLocalStorage";
import EditorHeader from "./Editor/EditorHeader";
import { useToast } from "@/hooks/useToast";
import 'primeicons/primeicons.css';
-const ResourceForm = () => {
- const [title, setTitle] = useState('');
- const [summary, setSummary] = useState('');
- const [isPaidResource, setIsPaidResource] = useState(false);
- const [price, setPrice] = useState(0);
- const [text, setText] = useState('');
- const [coverImage, setCoverImage] = useState('');
- const [topics, setTopics] = useState([]);
+const ResourceForm = ({ draft = null }) => {
+ const [title, setTitle] = useState(draft?.title || '');
+ const [summary, setSummary] = useState(draft?.summary || '');
+ const [isPaidResource, setIsPaidResource] = useState(draft?.price ? true : false);
+ const [price, setPrice] = useState(draft?.price || 0);
+ const [text, setText] = useState(draft?.content || '');
+ const [coverImage, setCoverImage] = useState(draft?.image || '');
+ const [topics, setTopics] = useState(draft?.topics || ['']);
const [user] = useLocalStorageWithEffect('user', {});
-
const { showToast } = useToast();
-
const { publishAll } = useNostr();
-
const router = useRouter();
+ useEffect(() => {
+ if (draft) {
+ setTitle(draft.title);
+ setSummary(draft.summary);
+ setIsPaidResource(draft.price ? true : false);
+ setPrice(draft.price || 0);
+ setText(draft.content);
+ setCoverImage(draft.image);
+ setTopics(draft.topics || []);
+ }
+ }, [draft]);
+
const handleSubmit = async (e) => {
e.preventDefault();
-
+
const userResponse = await axios.get(`/api/users/${user.pubkey}`);
-
+
if (!userResponse.data) {
showToast('error', 'Error', 'User not found', 'Please try again.');
return;
}
-
+
const payload = {
title,
summary,
@@ -48,16 +55,23 @@ const ResourceForm = () => {
price: isPaidResource ? price : null,
content: text,
image: coverImage,
- user: userResponse.data.id,
topics: [...topics.map(topic => topic.trim().toLowerCase()), 'plebdevs', 'resource']
};
-
- if (payload && payload.user) {
- axios.post('/api/drafts', payload)
+
+ if (!draft) {
+ // Only include user when creating a new draft
+ payload.user = userResponse.data.id;
+ }
+
+ if (payload) {
+ const url = draft ? `/api/drafts/${draft.id}` : '/api/drafts';
+ const method = draft ? 'put' : 'post';
+
+ axios[method](url, payload)
.then(response => {
- if (response.status === 201) {
- showToast('success', 'Success', 'Resource saved as draft.');
-
+ if (response.status === 200 || response.status === 201) {
+ showToast('success', 'Success', draft ? 'Resource updated successfully.' : 'Resource saved as draft.');
+
if (response.data?.id) {
router.push(`/draft/${response.data.id}`);
}
@@ -65,6 +79,7 @@ const ResourceForm = () => {
})
.catch(error => {
console.error(error);
+ showToast('error', 'Error', 'Failed to save resource. Please try again.');
});
}
};
@@ -219,11 +234,13 @@ const ResourceForm = () => {
setTopics(updatedTopics);
};
- const addTopic = () => {
+ const addTopic = (e) => {
+ e.preventDefault();
setTopics([...topics, '']); // Add an empty string to the topics array
};
- const removeTopic = (index) => {
+ const removeTopic = (e, index) => {
+ e.preventDefault();
const updatedTopics = topics.filter((_, i) => i !== index);
setTopics(updatedTopics);
};
@@ -296,7 +313,7 @@ const ResourceForm = () => {
handleTopicChange(index, e.target.value)} placeholder="Topic" className="w-full mt-2" />
{index > 0 && (
-
))}
@@ -305,7 +322,7 @@ const ResourceForm = () => {
-
+
);
diff --git a/src/components/forms/WorkshopForm.js b/src/components/forms/WorkshopForm.js
index 6b4b283..d8f7f51 100644
--- a/src/components/forms/WorkshopForm.js
+++ b/src/components/forms/WorkshopForm.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';
import { InputText } from 'primereact/inputtext';
@@ -9,21 +9,31 @@ import { useToast } from '@/hooks/useToast';
import { useLocalStorageWithEffect } from '@/hooks/useLocalStorage';
import 'primeicons/primeicons.css';
-const WorkshopForm = () => {
- const [title, setTitle] = useState('');
- const [summary, setSummary] = useState('');
- const [price, setPrice] = useState(0);
- const [isPaidResource, setIsPaidResource] = useState(false);
- const [videoUrl, setVideoUrl] = useState('');
- const [coverImage, setCoverImage] = useState('');
- const [topics, setTopics] = useState(['']);
+const WorkshopForm = ({ draft = null }) => {
+ const [title, setTitle] = useState(draft?.title || '');
+ const [summary, setSummary] = useState(draft?.summary || '');
+ const [price, setPrice] = useState(draft?.price || 0);
+ const [isPaidResource, setIsPaidResource] = useState(draft?.price ? true : false);
+ const [videoUrl, setVideoUrl] = useState(draft?.content || '');
+ const [coverImage, setCoverImage] = useState(draft?.image || '');
+ const [topics, setTopics] = useState(draft?.topics || ['']);
const router = useRouter();
-
const [user] = useLocalStorageWithEffect('user', {});
-
const { showToast } = useToast();
+ useEffect(() => {
+ if (draft) {
+ setTitle(draft.title);
+ setSummary(draft.summary);
+ setPrice(draft.price || 0);
+ setIsPaidResource(draft.price ? true : false);
+ setVideoUrl(draft.content);
+ setCoverImage(draft.image);
+ setTopics(draft.topics || ['']);
+ }
+ }, [draft]);
+
const handleSubmit = async (e) => {
e.preventDefault();
let embedCode = '';
@@ -59,10 +69,13 @@ const WorkshopForm = () => {
};
if (payload && payload.user) {
- axios.post('/api/drafts', payload)
+ const url = draft ? `/api/drafts/${draft.id}` : '/api/drafts';
+ const method = draft ? 'put' : 'post';
+
+ axios[method](url, payload)
.then(response => {
- if (response.status === 201) {
- showToast('success', 'Success', 'Workshop saved as draft.');
+ if (response.status === 200 || response.status === 201) {
+ showToast('success', 'Success', draft ? 'Workshop updated successfully.' : 'Workshop saved as draft.');
if (response.data?.id) {
router.push(`/draft/${response.data.id}`);
@@ -71,6 +84,7 @@ const WorkshopForm = () => {
})
.catch(error => {
console.error(error);
+ showToast('error', 'Error', 'Failed to save workshop. Please try again.');
});
}
};
@@ -85,11 +99,13 @@ const WorkshopForm = () => {
setTopics(updatedTopics);
};
- const addTopic = () => {
+ const addTopic = (e) => {
+ e.preventDefault();
setTopics([...topics, '']); // Add an empty string to the topics array
};
- const removeTopic = (index) => {
+ const removeTopic = (e, index) => {
+ e.preventDefault();
const updatedTopics = topics.filter((_, i) => i !== index);
setTopics(updatedTopics);
};
@@ -125,7 +141,7 @@ const WorkshopForm = () => {
handleTopicChange(index, e.target.value)} placeholder="Topic" className="w-full mt-2" />
{index > 0 && (
- removeTopic(index)} />
+ removeTopic(e, index)} />
)}
))}
@@ -134,7 +150,7 @@ const WorkshopForm = () => {
-
+
);
diff --git a/src/db/models/draftModels.js b/src/db/models/draftModels.js
index ae2ad61..dc16d47 100644
--- a/src/db/models/draftModels.js
+++ b/src/db/models/draftModels.js
@@ -33,9 +33,15 @@ export const createDraft = async (data) => {
export const updateDraft = async (id, data) => {
+ const { user, ...otherData } = data;
return await prisma.draft.update({
where: { id },
- data,
+ data: {
+ ...otherData,
+ user: user ? {
+ connect: { id: user }
+ } : undefined
+ },
});
};
diff --git a/src/pages/draft/[slug]/edit.js b/src/pages/draft/[slug]/edit.js
new file mode 100644
index 0000000..39a7925
--- /dev/null
+++ b/src/pages/draft/[slug]/edit.js
@@ -0,0 +1,37 @@
+import React, { useState, useEffect } from "react";
+import { useRouter } from "next/router";
+import axios from "axios";
+import ResourceForm from "@/components/forms/ResourceForm";
+import WorkshopForm from "@/components/forms/WorkshopForm";
+import CourseForm from "@/components/forms/CourseForm";
+
+const Edit = () => {
+ const [draft, setDraft] = useState(null);
+ const router = useRouter();
+
+ useEffect(() => {
+ if (router.isReady) {
+ const { slug } = router.query;
+
+ axios.get(`/api/drafts/${slug}`)
+ .then(res => {
+ console.log('res:', res.data);
+ setDraft(res.data);
+ })
+ .catch(err => {
+ console.error(err);
+ });
+ }
+ }, [router.isReady, router.query]);
+
+ return (
+
+
Edit Draft
+ {draft?.type === 'course' && }
+ {draft?.type === 'workshop' && }
+ {draft?.type === 'resource' && }
+
+ );
+};
+
+export default Edit;
diff --git a/src/pages/draft/[slug].js b/src/pages/draft/[slug]/index.js
similarity index 91%
rename from src/pages/draft/[slug].js
rename to src/pages/draft/[slug]/index.js
index 88c8929..c4e74eb 100644
--- a/src/pages/draft/[slug].js
+++ b/src/pages/draft/[slug]/index.js
@@ -18,10 +18,20 @@ import ReactMarkdown from 'react-markdown';
import rehypeRaw from 'rehype-raw';
const MarkdownContent = ({ content }) => {
+ // Function to strip HTML tags
+ const stripHtml = (html) => {
+ let tmp = document.createElement("DIV");
+ tmp.innerHTML = html;
+ return tmp.textContent || tmp.innerText || "";
+ };
+
+ // Strip HTML tags from the content
+ const plainContent = stripHtml(content);
+
return (
- {content}
+ {plainContent}
);
@@ -148,7 +158,6 @@ export default function Details() {
let event = {};
let type;
let encryptedContent;
- console.log('draft:', draft);
switch (draft?.type) {
case 'resource':
@@ -243,12 +252,14 @@ export default function Details() {
height={50}
className="rounded-full mr-4"
/>
-
+ {user && user?.pubkey && (
+
Created by{' '}
-
- {user?.username}
+
+ {user?.username || user?.pubkey.slice(0, 10)}{'... '}
+ )}
@@ -270,7 +281,10 @@ export default function Details() {
-
+
+ router.push(`/draft/${draft?.id}/edit`)} label="Edit" severity='warning' outlined className="w-auto my-2" />
+
+
{
diff --git a/src/styles/globals.css b/src/styles/globals.css
index 08c8c2b..38de488 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -89,4 +89,26 @@ h3 {
.p-tabmenu .p-tabmenu-nav::-webkit-scrollbar {
display: none;
+}
+
+/* markdown content display styles */
+.markdown-content {
+ font-family: Arial, sans-serif;
+ line-height: 1.6;
+}
+
+.markdown-content h1, .markdown-content h2 {
+ padding-bottom: 0.3em;
+}
+
+.markdown-content pre {
+ border-radius: 3px;
+ padding: 16px;
+ overflow: auto;
+}
+
+.markdown-content code {
+ border-radius: 3px;
+ font-size: 85%;
+ margin: 0;
}
\ No newline at end of file