This commit is contained in:
		| @@ -26,6 +26,7 @@ export default function PostSummary({ | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|  |     <> | ||||||
|       <div |       <div | ||||||
|         key={metadata.slug} |         key={metadata.slug} | ||||||
|         style={{ |         style={{ | ||||||
| @@ -190,5 +191,36 @@ export default function PostSummary({ | |||||||
|           </span> |           </span> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|  |       {loggedIn ? ( | ||||||
|  |         <div | ||||||
|  |           style={{ | ||||||
|  |             marginTop: "2rem", | ||||||
|  |             padding: "0.5rem 1rem", | ||||||
|  |             backgroundColor: "#333", | ||||||
|  |             width: "fit-content", | ||||||
|  |             userSelect: "none", | ||||||
|  |             cursor: "pointer", | ||||||
|  |           }} | ||||||
|  |           onClick={() => router.push("/blog/write")} | ||||||
|  |         > | ||||||
|  |           write a post | ||||||
|  |         </div> | ||||||
|  |       ) : ( | ||||||
|  |         <div | ||||||
|  |           style={{ | ||||||
|  |             marginTop: "2rem", | ||||||
|  |             padding: "0.3rem 0.5rem", | ||||||
|  |             backgroundColor: "#333", | ||||||
|  |             width: "fit-content", | ||||||
|  |             userSelect: "none", | ||||||
|  |             cursor: "pointer", | ||||||
|  |             fontSize: "0.8rem", | ||||||
|  |           }} | ||||||
|  |           onClick={() => router.push("/blog/login")} | ||||||
|  |         > | ||||||
|  |           login | ||||||
|  |         </div> | ||||||
|  |       )} | ||||||
|  |     </> | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -57,7 +57,7 @@ export async function getSummaries( | |||||||
|       ...filter, |       ...filter, | ||||||
|       omit: { contentMarkdown: true, contentRendered: true }, |       omit: { contentMarkdown: true, contentRendered: true }, | ||||||
|       include: { tags: { select: { name: true } } }, |       include: { tags: { select: { name: true } } }, | ||||||
|       orderBy: { publishedDate: "asc" }, |       orderBy: { publishedDate: "desc" }, | ||||||
|       skip: PAGE_SIZE * (pageNumber - 1), |       skip: PAGE_SIZE * (pageNumber - 1), | ||||||
|       take: PAGE_SIZE, |       take: PAGE_SIZE, | ||||||
|     }) |     }) | ||||||
| @@ -79,3 +79,19 @@ export async function unpublishArticle(slug: string) { | |||||||
|   const prisma = new PrismaClient(); |   const prisma = new PrismaClient(); | ||||||
|   await prisma.post.update({ where: { slug }, data: { is_draft: true } }); |   await prisma.post.update({ where: { slug }, data: { is_draft: true } }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export async function deleteArticle(slug: string) { | ||||||
|  |   const prisma = new PrismaClient(); | ||||||
|  |   const post = await prisma.post.delete({ | ||||||
|  |     where: { slug }, | ||||||
|  |     include: { tags: true }, | ||||||
|  |   }); | ||||||
|  |   for (const tag of post.tags) { | ||||||
|  |     const postsWithTag = await prisma.post.count({ | ||||||
|  |       where: { tags: { some: { id: tag.id } } }, | ||||||
|  |     }); | ||||||
|  |     if (postsWithTag == 0) { | ||||||
|  |       await prisma.tag.delete({ where: { id: tag.id } }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -3,7 +3,8 @@ | |||||||
| import { useRouter } from "next/navigation"; | import { useRouter } from "next/navigation"; | ||||||
| import * as Types from "../../types"; | import * as Types from "../../types"; | ||||||
| import "highlight.js/styles/github-dark.css"; | import "highlight.js/styles/github-dark.css"; | ||||||
| import { publishArticle, unpublishArticle } from "../../action"; | import { deleteArticle, publishArticle, unpublishArticle } from "../../action"; | ||||||
|  | import { useState } from "react"; | ||||||
|  |  | ||||||
| export default function PostDisplay({ | export default function PostDisplay({ | ||||||
|   post, |   post, | ||||||
| @@ -13,6 +14,9 @@ export default function PostDisplay({ | |||||||
|   loggedIn: boolean; |   loggedIn: boolean; | ||||||
| }) { | }) { | ||||||
|   const router = useRouter(); |   const router = useRouter(); | ||||||
|  |  | ||||||
|  |   const [confirmDelete, setConfirmDelete] = useState(false); | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <div |       <div | ||||||
| @@ -151,6 +155,27 @@ export default function PostDisplay({ | |||||||
|         }} |         }} | ||||||
|       > |       > | ||||||
|         {loggedIn ? ( |         {loggedIn ? ( | ||||||
|  |           <div style={{ display: "flex", gap: "1rem" }}> | ||||||
|  |             <div | ||||||
|  |               style={{ | ||||||
|  |                 backgroundColor: "#6a6", | ||||||
|  |                 color: "#111", | ||||||
|  |                 fontSize: "0.8rem", | ||||||
|  |                 padding: "0.5rem", | ||||||
|  |                 transition: "background-color 0.3s linear", | ||||||
|  |                 userSelect: "none", | ||||||
|  |                 cursor: "pointer", | ||||||
|  |               }} | ||||||
|  |               onMouseOver={(e) => { | ||||||
|  |                 e.currentTarget.style.backgroundColor = "#8c8"; | ||||||
|  |               }} | ||||||
|  |               onMouseOut={(e) => { | ||||||
|  |                 e.currentTarget.style.backgroundColor = "#6a6"; | ||||||
|  |               }} | ||||||
|  |               onClick={() => router.push(`/blog/write/${post.slug}`)} | ||||||
|  |             > | ||||||
|  |               edit | ||||||
|  |             </div> | ||||||
|             <div |             <div | ||||||
|               style={{ |               style={{ | ||||||
|                 backgroundColor: "#a66", |                 backgroundColor: "#a66", | ||||||
| @@ -167,9 +192,18 @@ export default function PostDisplay({ | |||||||
|               onMouseOut={(e) => { |               onMouseOut={(e) => { | ||||||
|                 e.currentTarget.style.backgroundColor = "#a66"; |                 e.currentTarget.style.backgroundColor = "#a66"; | ||||||
|               }} |               }} | ||||||
|             onClick={() => router.push(`/blog/write/${post.slug}`)} |               onClick={() => setConfirmDelete(true)} | ||||||
|             > |             > | ||||||
|             edit |               delete | ||||||
|  |             </div> | ||||||
|  |             <DeleteModal | ||||||
|  |               open={confirmDelete} | ||||||
|  |               onCancel={() => setConfirmDelete(false)} | ||||||
|  |               onConfirm={async () => { | ||||||
|  |                 await deleteArticle(post.slug); | ||||||
|  |                 router.push("/blog"); | ||||||
|  |               }} | ||||||
|  |             /> | ||||||
|           </div> |           </div> | ||||||
|         ) : ( |         ) : ( | ||||||
|           <div></div> |           <div></div> | ||||||
| @@ -198,3 +232,96 @@ export default function PostDisplay({ | |||||||
|     </> |     </> | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function DeleteModal({ | ||||||
|  |   open, | ||||||
|  |   onCancel, | ||||||
|  |   onConfirm, | ||||||
|  | }: { | ||||||
|  |   open: boolean; | ||||||
|  |   onCancel: () => void; | ||||||
|  |   onConfirm: () => void; | ||||||
|  | }) { | ||||||
|  |   return ( | ||||||
|  |     <div | ||||||
|  |       id="deleteModal" | ||||||
|  |       style={{ | ||||||
|  |         display: open | ||||||
|  |           ? "flex" | ||||||
|  |           : "none" /* Will be changed to "flex" when opened */, | ||||||
|  |         position: "fixed", | ||||||
|  |         top: 0, | ||||||
|  |         left: 0, | ||||||
|  |         width: "100%", | ||||||
|  |         height: "100%", | ||||||
|  |         backgroundColor: "rgba(0, 0, 0, 0.7)", | ||||||
|  |         zIndex: 1000, | ||||||
|  |         justifyContent: "center", | ||||||
|  |         alignItems: "center", | ||||||
|  |       }} | ||||||
|  |       onClick={(e) => { | ||||||
|  |         if (e.target == e.currentTarget) { | ||||||
|  |           onCancel(); | ||||||
|  |         } | ||||||
|  |       }} | ||||||
|  |     > | ||||||
|  |       <div | ||||||
|  |         style={{ | ||||||
|  |           backgroundColor: "#222", | ||||||
|  |           padding: "1.5rem", | ||||||
|  |           borderRadius: "4px", | ||||||
|  |           maxWidth: "400px", | ||||||
|  |           width: "90%", | ||||||
|  |           boxShadow: "0 0 10px rgba(0, 0, 0, 0.5)", | ||||||
|  |         }} | ||||||
|  |         onClick={(e) => e.stopPropagation()} | ||||||
|  |       > | ||||||
|  |         <h3 style={{ margin: "0 0 1rem 0", color: "#eee" }}> | ||||||
|  |           Confirm Deletion | ||||||
|  |         </h3> | ||||||
|  |         <p style={{ marginBottom: "1.5rem", color: "#ccc" }}> | ||||||
|  |           Are you sure you want to delete this post? This action cannot be | ||||||
|  |           undone. | ||||||
|  |         </p> | ||||||
|  |         <div | ||||||
|  |           style={{ | ||||||
|  |             display: "flex", | ||||||
|  |             justifyContent: "flex-end", | ||||||
|  |             gap: "0.75rem", | ||||||
|  |           }} | ||||||
|  |         > | ||||||
|  |           <button | ||||||
|  |             style={{ | ||||||
|  |               backgroundColor: "#a66", | ||||||
|  |               color: "#fff", | ||||||
|  |               border: "none", | ||||||
|  |               padding: "0.5rem 1rem", | ||||||
|  |               cursor: "pointer", | ||||||
|  |               borderRadius: "2px", | ||||||
|  |             }} | ||||||
|  |             onClick={() => { | ||||||
|  |               onConfirm(); | ||||||
|  |             }} | ||||||
|  |           > | ||||||
|  |             Yes, delete it | ||||||
|  |           </button> | ||||||
|  |           <button | ||||||
|  |             style={{ | ||||||
|  |               backgroundColor: "#555", | ||||||
|  |               color: "#fff", | ||||||
|  |               border: "none", | ||||||
|  |               padding: "0.5rem 1rem", | ||||||
|  |               cursor: "pointer", | ||||||
|  |               borderRadius: "2px", | ||||||
|  |             }} | ||||||
|  |             onClick={() => { | ||||||
|  |               onCancel(); | ||||||
|  |             }} | ||||||
|  |           > | ||||||
|  |             Cancel | ||||||
|  |           </button> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user