From 1ab8022b951cab5405f74a927008e0649a6a7e25 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 2 Dec 2024 22:06:55 +0300 Subject: [PATCH] Post update stuff --- enshi/src/@types/UserType.ts | 1 + .../ArticleViewer/ArticleViewer.tsx | 29 +++++-- .../ChangePostButton/ChangePostButton.tsx | 21 ++++++ .../SkeletonLoader/SkeletonLoader.tsx | 2 +- enshi/src/Components/Editor/Editor.tsx | 49 +++++++----- .../LoginRegisterPage/LoginPage/LoginPage.tsx | 2 + .../PostRedactor/PostRedactor.tsx | 75 +++++++++++++++++++ .../SubmitChangesButton.tsx | 57 ++++++++++++++ .../RegisterPage/RegisterPage.tsx | 3 +- enshi/src/Pages/MainPage/MainPage.tsx | 1 + enshi/src/routes/routes.tsx | 2 + enshi_back/routes/authRoutes/login.go | 2 +- enshi_back/routes/authRoutes/registerUser.go | 2 +- enshi_back/routes/routesSetup.go | 1 + 14 files changed, 217 insertions(+), 30 deletions(-) create mode 100644 enshi/src/Components/ArticleViewer/ChangePostButton/ChangePostButton.tsx create mode 100644 enshi/src/Pages/LoginRegisterPage/PostRedactor/PostRedactor.tsx create mode 100644 enshi/src/Pages/LoginRegisterPage/PostRedactor/SubmitChangesButton/SubmitChangesButton.tsx diff --git a/enshi/src/@types/UserType.ts b/enshi/src/@types/UserType.ts index c48416c..0e20c4d 100644 --- a/enshi/src/@types/UserType.ts +++ b/enshi/src/@types/UserType.ts @@ -1,4 +1,5 @@ export type TUser = { username: string; isAdmin: boolean; + id?: string | number; } \ No newline at end of file diff --git a/enshi/src/Components/ArticleViewer/ArticleViewer.tsx b/enshi/src/Components/ArticleViewer/ArticleViewer.tsx index 564e314..5e6cb85 100644 --- a/enshi/src/Components/ArticleViewer/ArticleViewer.tsx +++ b/enshi/src/Components/ArticleViewer/ArticleViewer.tsx @@ -1,9 +1,12 @@ -import { Container, Separator, Text } from "@radix-ui/themes"; +import { Container, Flex, Separator, Text } from "@radix-ui/themes"; import { useQuery } from "@tanstack/react-query"; import { Interweave } from "interweave"; +import { useAtomValue } from "jotai"; import { useParams } from "react-router-dom"; import { axiosLocalhost } from "../../api/axios/axios"; -import SkeletonLoader from "./SkeletonLoader/SkeletonLoader"; +import { userAtom } from "../../AtomStore/AtomStore"; +import ChangePostButton from "./ChangePostButton/ChangePostButton"; +import SkeletonPostLoader from "./SkeletonLoader/SkeletonLoader"; type TArticleViewer = { htmlToParse?: string; @@ -11,6 +14,7 @@ type TArticleViewer = { export default function ArticleViewer(props: TArticleViewer) { let queryParams = useParams(); + const user = useAtomValue(userAtom) const { data, isPending } = useQuery({ queryKey: [`post_${queryParams["postId"]}`], @@ -21,18 +25,27 @@ export default function ArticleViewer(props: TArticleViewer) { return response.data; }, - }); + }) + - if (isPending) - return ( - - ); + if (isPending) return ; return ( <>
- {data.title} + + + {data.title} + + + + + diff --git a/enshi/src/Components/ArticleViewer/ChangePostButton/ChangePostButton.tsx b/enshi/src/Components/ArticleViewer/ChangePostButton/ChangePostButton.tsx new file mode 100644 index 0000000..f76cc5e --- /dev/null +++ b/enshi/src/Components/ArticleViewer/ChangePostButton/ChangePostButton.tsx @@ -0,0 +1,21 @@ +import { Button } from "@radix-ui/themes"; +import { useNavigate } from "react-router-dom"; + +type TChangePostButton = { + postId: number | string; +}; + +export default function ChangePostButton(props: TChangePostButton) { + const navigate = useNavigate(); + + return ( + + ); +} diff --git a/enshi/src/Components/ArticleViewer/SkeletonLoader/SkeletonLoader.tsx b/enshi/src/Components/ArticleViewer/SkeletonLoader/SkeletonLoader.tsx index 2a9841b..efa6b31 100644 --- a/enshi/src/Components/ArticleViewer/SkeletonLoader/SkeletonLoader.tsx +++ b/enshi/src/Components/ArticleViewer/SkeletonLoader/SkeletonLoader.tsx @@ -5,7 +5,7 @@ import { pText, } from "../../../constants/textForSkeleton"; -export default function SkeletonLoader() { +export default function SkeletonPostLoader() { return ( diff --git a/enshi/src/Components/Editor/Editor.tsx b/enshi/src/Components/Editor/Editor.tsx index a758d13..dd5354d 100644 --- a/enshi/src/Components/Editor/Editor.tsx +++ b/enshi/src/Components/Editor/Editor.tsx @@ -1,11 +1,6 @@ import Sources from "quill"; import Quill, { Delta } from "quill/core"; -import { - forwardRef, - useEffect, - useRef, - useState -} from "react"; +import { forwardRef, useEffect, useRef, useState } from "react"; import ReactQuill from "react-quill"; type TEditor = { @@ -28,7 +23,7 @@ const modules = { ["link", "image"], ["clean"], [{ align: [] }], - ] + ], }; /** @@ -37,7 +32,9 @@ const modules = { const Editor = forwardRef((props: TEditor) => { const editor = useRef(null); const [quill, setQuill] = useState(null); - const [value, setValue] = useState(new Delta()) + const [value, setValue] = useState(new Delta()); + + const [loaded, setLoaded] = useState(false); useEffect(() => { if (editor.current) { @@ -49,15 +46,34 @@ const Editor = forwardRef((props: TEditor) => { setQuill(null); }; }, [editor.current]); - - const changeHandler = (val: string, _changeDelta: Delta, _source: Sources, _editor: ReactQuill.UnprivilegedEditor) => { + useEffect(() => { + const quill = new Quill(document.createElement("div")); + const t = quill.clipboard.convert({ + html: props.defaultValue as string, + }) as Delta; + + if (!loaded) { + setValue(t); + + console.log(t); + } + + setLoaded(true); + }, [props.defaultValue]); + + const changeHandler = ( + val: string, + _changeDelta: Delta, + _source: Sources, + _editor: ReactQuill.UnprivilegedEditor + ) => { console.log(val); - console.log(JSON.stringify(quill?.getContents().ops, null, 2)) - let fullDelta = quill?.getContents() - if (props.onChange) props.onChange(val || "") - setValue(fullDelta || new Delta()) - } + console.log(JSON.stringify(quill?.getContents().ops, null, 2)); + let fullDelta = quill?.getContents(); + if (props.onChange) props.onChange(val || ""); + if (loaded) setValue(fullDelta || new Delta()); + }; return (
@@ -65,10 +81,7 @@ const Editor = forwardRef((props: TEditor) => { value={value} ref={editor} modules={modules} - onChange={changeHandler} - - theme="snow" placeholder="Type your thoughts here..." /> diff --git a/enshi/src/Pages/LoginRegisterPage/LoginPage/LoginPage.tsx b/enshi/src/Pages/LoginRegisterPage/LoginPage/LoginPage.tsx index 7835c87..2b1e3db 100644 --- a/enshi/src/Pages/LoginRegisterPage/LoginPage/LoginPage.tsx +++ b/enshi/src/Pages/LoginRegisterPage/LoginPage/LoginPage.tsx @@ -33,6 +33,7 @@ export default function LoginPage() { setUserAtom({ username: response.data.username, isAdmin: false, + id: response.data.id, }); }, @@ -48,6 +49,7 @@ export default function LoginPage() { setUserAtom({ username: userAtomValue?.username || "", isAdmin: true, + id: userAtomValue?.id, }); } }; diff --git a/enshi/src/Pages/LoginRegisterPage/PostRedactor/PostRedactor.tsx b/enshi/src/Pages/LoginRegisterPage/PostRedactor/PostRedactor.tsx new file mode 100644 index 0000000..c7cafaa --- /dev/null +++ b/enshi/src/Pages/LoginRegisterPage/PostRedactor/PostRedactor.tsx @@ -0,0 +1,75 @@ +import { Box, Container, Flex, Spinner } from "@radix-ui/themes"; +import { useQuery } from "@tanstack/react-query"; +import { useState } from "react"; +import { useParams } from "react-router-dom"; +import { axiosLocalhost } from "../../../api/axios/axios"; +import Editor from "../../../Components/Editor/Editor"; +import SubmitChangesButton from "./SubmitChangesButton/SubmitChangesButton"; + +export default function PostRedactor() { + const [contentValue, setContentValue] = useState(""); + const [titleValue, setTitleValue] = useState(""); + + const queryParams = useParams(); + + const { isPending } = useQuery({ + queryKey: ["changePostKey", queryParams.postId], + queryFn: async () => { + try { + const response = await axiosLocalhost.get( + `/posts/${queryParams.postId}` + ); + + setTitleValue(response.data["title"]); + setContentValue(response.data["content"]); + + return response.data; + } catch (error) { + console.log(error); + + return error; + } + }, + gcTime: Infinity, + }); + + return ( + <> + + + + { + setTitleValue(e.target.value); + }} + value={titleValue} + /> + + + + {isPending ? ( + + ) : ( + + )} + + + + + + + + + ); +} diff --git a/enshi/src/Pages/LoginRegisterPage/PostRedactor/SubmitChangesButton/SubmitChangesButton.tsx b/enshi/src/Pages/LoginRegisterPage/PostRedactor/SubmitChangesButton/SubmitChangesButton.tsx new file mode 100644 index 0000000..52cddc8 --- /dev/null +++ b/enshi/src/Pages/LoginRegisterPage/PostRedactor/SubmitChangesButton/SubmitChangesButton.tsx @@ -0,0 +1,57 @@ +import { Button } from "@radix-ui/themes"; +import { useMutation } from "@tanstack/react-query"; +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useNavigate, useParams } from "react-router-dom"; +import { axiosLocalhost } from "../../../../api/axios/axios"; + +type TSubmitChangesButton = { + className: string; + titleValue: string; + contentValue: string; +}; + +export default function SubmitChangesButton(props: TSubmitChangesButton) { + const { t } = useTranslation(); + + const [isDisabled, setIsDisabled] = useState(false); + + const navigate = useNavigate(); + const queryParams = useParams(); + + const postMutation = useMutation({ + mutationFn: async () => { + if (!props.titleValue) throw new Error("no title provided"); + if (!props.contentValue || props.contentValue === "


") + throw new Error("no content provided"); + + axiosLocalhost.put(`/posts/${queryParams["postId"]}`, { + title: props.titleValue, + content: props.contentValue, + }); + }, + onMutate: () => { + setIsDisabled(true); + }, + onError: () => { + setIsDisabled(false); + }, + onSuccess: () => { + navigate("/"); + }, + }); + + return ( + + ); +} diff --git a/enshi/src/Pages/LoginRegisterPage/RegisterPage/RegisterPage.tsx b/enshi/src/Pages/LoginRegisterPage/RegisterPage/RegisterPage.tsx index bd488f4..787d581 100644 --- a/enshi/src/Pages/LoginRegisterPage/RegisterPage/RegisterPage.tsx +++ b/enshi/src/Pages/LoginRegisterPage/RegisterPage/RegisterPage.tsx @@ -34,7 +34,8 @@ export default function RegisterPage() { let response = await axiosLocalhost.post("/users", JSON.stringify(data)); setUserAtom({ username: response.data.username, - isAdmin: false + isAdmin: false, + id: response.data.id, }) }, diff --git a/enshi/src/Pages/MainPage/MainPage.tsx b/enshi/src/Pages/MainPage/MainPage.tsx index 12bb82d..bf710a8 100644 --- a/enshi/src/Pages/MainPage/MainPage.tsx +++ b/enshi/src/Pages/MainPage/MainPage.tsx @@ -24,6 +24,7 @@ export default function MainPage() { setUserData({ isAdmin: response.data["is_admin"], username: response.data["username"], + id: response.data["id"], }); return true; } catch (error) { diff --git a/enshi/src/routes/routes.tsx b/enshi/src/routes/routes.tsx index fd1c62a..a8f2323 100644 --- a/enshi/src/routes/routes.tsx +++ b/enshi/src/routes/routes.tsx @@ -7,6 +7,7 @@ import { import ArticleViewer from "../Components/ArticleViewer/ArticleViewer"; import AuthPageWrapper from "../Pages/AuthPageWrapper/AuthPageWrapper"; import LoginPage from "../Pages/LoginRegisterPage/LoginPage/LoginPage"; +import PostRedactor from "../Pages/LoginRegisterPage/PostRedactor/PostRedactor"; import RegisterPage from "../Pages/LoginRegisterPage/RegisterPage/RegisterPage"; import MainPage from "../Pages/MainPage/MainPage"; import PostCreatorPage from "../Pages/PostCreatorPage/PostCreatorPage"; @@ -40,6 +41,7 @@ export const routes = createRoutesFromElements( /> } /> + } />