diff --git a/components/admin/AddChapter.jsx b/components/admin/AddChapter.jsx index fdafdbc..b0a1c06 100644 --- a/components/admin/AddChapter.jsx +++ b/components/admin/AddChapter.jsx @@ -1,6 +1,7 @@ import { storage, store } from "@fb/client"; import { yupResolver } from "@hookform/resolvers/yup"; import { chapterFormValues, chapterValidator } from "@lib/validators"; +import { refreshPages } from "@services/client"; import axios from "axios"; import { collection, @@ -56,27 +57,12 @@ export default function AddChapter({ onCompleted }) { } }, [selectedStory, setValue]); - const refreshPages = async ({ refreshPassword }) => { - setProcessing("Refreshing Story..."); - try { - await axios.post("/api/revalidate", { - pwd: refreshPassword, - updateType: [`stories/${selectedStory.id}`], - }); - setProcessing("Processing Completed."); - setTimeout(() => { - reset(); - onCompleted(); - }, 500); - } catch (error) { - console.error(error); - } - }; - const addChapterDoc = async (snapshotRef, values) => { setProcessing("Creating Chapter..."); try { const fileUrl = await getDownloadURL(snapshotRef); + + // Payload for creating new chapter const chapter = { author: values.author, excerpt: values.excerpt, @@ -86,29 +72,52 @@ export default function AddChapter({ onCompleted }) { title: values.title, content: fileUrl, }; - const chapterRef = doc( - store, - "stories", - selectedStory.id, - "chapters", - values.chapterId - ); - await setDoc(chapterRef, chapter); - - setProcessing("Updating Story Info..."); - const storyUpdatePayload = { + // Payload for updating story + const storyUpdate = { lastUpdated: Timestamp.fromDate(new Date()), chapterSlugs: [...selectedStory.chapterSlugs, values.chapterId], wip: !values.markCompleted, draft: false, }; if (chapter.order === 1) - storyUpdatePayload.published = Timestamp.fromDate(new Date()); + storyUpdate.published = Timestamp.fromDate(new Date()); + + // New Chapter Reference + const newChapter = doc( + store, + "stories", + selectedStory.id, + "chapters", + values.chapterId + ); + // Previous Chapter Reference + const prevChapter = doc( + store, + "stories", + selectedStory.id, + "chapters", + values.previousChapter + ); + // Story Reference const storyRef = doc(store, "stories", selectedStory.id); - await setDoc(storyRef, storyUpdatePayload, { merge: true }); - setProcessing("Story Updated."); - refreshPages(values); + // Update All in parallel. + await Promise.all([ + setDoc(newChapter, chapter), + setDoc(prevChapter, { nextChapter: values.chapterId }, { merge: true }), + setDoc(storyRef, storyUpdate, { merge: true }), + ]); + + setProcessing("Refreshing Story..."); + await refreshPages(values.refreshPassword, [ + `stories/${selectedStory.id}`, + `stories/${selectedStory.id}/${values.previousChapter}`, + ]); + setProcessing("Processing Completed."); + setTimeout(() => { + reset(); + onCompleted(); + }, 500); } catch (error) { console.error(error); } diff --git a/components/admin/AddPost.jsx b/components/admin/AddPost.jsx index e1047c9..15c2814 100644 --- a/components/admin/AddPost.jsx +++ b/components/admin/AddPost.jsx @@ -70,14 +70,14 @@ export default function AddPost({ onCompleted }) { if (!formValues.draft) post.published = Timestamp.fromDate(new Date()); delete post.postId; - delete post.refreshPassword; // TODO: + delete post.refreshPassword; const docRef = doc(store, "posts", formValues.postId); await setDoc(docRef, post); if (!formValues.draft) { await await axios.post("/api/revalidate", { pwd: formValues.refreshPassword, - updateType: ["posts"], + paths: ["posts"], }); } setProcessing("Completed."); diff --git a/components/admin/Comments.jsx b/components/admin/Comments.jsx index 4f1ed11..02ab2c3 100644 --- a/components/admin/Comments.jsx +++ b/components/admin/Comments.jsx @@ -1,6 +1,7 @@ import { DATE_FORMATS } from "@constants/app"; import { store } from "@fb/client"; -import { IconCheck, IconPoint, IconTrash } from "@tabler/icons"; +import { refreshPages } from "@services/client"; +import { IconCheck, IconLoader3, IconPoint, IconTrash } from "@tabler/icons"; import dayjs from "dayjs"; import { collection, @@ -14,10 +15,33 @@ import { } from "firebase/firestore"; import Link from "next/link"; import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; import styles from "../../styles/modules/Admin.module.scss"; +import * as yup from "yup"; +import { yupResolver } from "@hookform/resolvers/yup"; export default function Comments() { const [comments, setComments] = useState([]); + const [processing, setProcessing] = useState(""); + const [selectedComments, setSelectedComments] = useState([]); + const [workingSet, setWorkingSet] = useState(""); + + const handleSelection = (e) => { + if (e.target.checked) { + setSelectedComments((prev) => [...prev, e.target.value]); + if (!workingSet) { + const commentInfo = comments.find((i) => i.id === e.target.value); + setWorkingSet(`${commentInfo.type}/${commentInfo.target}`); + } + } else { + const remainingComments = selectedComments.filter( + (c) => c !== e.target.value + ); + setSelectedComments(remainingComments); + if (remainingComments.length === 0) setWorkingSet(""); + } + }; + useEffect(() => { const q = query( collection(store, "comments"), @@ -35,14 +59,62 @@ export default function Comments() { }); }, []); - const approveComment = async (cId) => { - const cRef = doc(store, "comments", cId); - await updateDoc(cRef, { approved: true }); + const { + register, + getValues, + setError, + formState: { errors, isValid }, + } = useForm({ + mode: "onBlur", + shouldFocusError: true, + defaultValues: { + refreshPassword: "", + }, + resolver: yupResolver( + yup.object().shape({ + refreshPassword: yup.string().required(), + }) + ), + }); + + const approveComments = async () => { + try { + setProcessing("Approving..."); + if (!getValues("refreshPassword")) { + setError( + "refreshPassword", + { type: "required", message: "Required" }, + { shouldFocus: true } + ); + return; + } + await Promise.all( + selectedComments.map((comment) => { + return updateDoc(doc(store, "comments", comment), { approved: true }); + }) + ); + setProcessing("Refreshing Pages..."); + await refreshPages(getValues("refreshPassword"), [workingSet]); + setSelectedComments([]); + setWorkingSet(""); + } catch (error) { + console.log(error); + } }; - const deleteComment = async (cId) => { - const cRef = doc(store, "comments", cId); - await deleteDoc(cRef); + const deleteComments = async () => { + try { + setProcessing("Deleting..."); + await Promise.all( + selectedComments.map((comment) => { + return deleteDoc(doc(store, "comments", comment)); + }) + ); + setSelectedComments([]); + setWorkingSet(""); + } catch (error) { + console.log(error); + } }; if (!comments.length) @@ -55,50 +127,96 @@ export default function Comments() { ); return ( -
{c.userName}
-- {c.email || "---No Email---"} +
+ Selected Comments For:{" "} + {workingSet} +
+ )} + +{c.userName}
++ {c.email || "---No Email---"} +
+{c.body || "---No Body---"}
+
+ {dayjs(c.date).format(DATE_FORMATS.date)}
+
+
{c.body || "---No Body---"}
-
- {dayjs(c.date).format(DATE_FORMATS.date)}
-
-