Post update stuff
This commit is contained in:
parent
c8967df573
commit
1ab8022b95
@ -1,4 +1,5 @@
|
||||
export type TUser = {
|
||||
username: string;
|
||||
isAdmin: boolean;
|
||||
id?: string | number;
|
||||
}
|
||||
@ -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 (
|
||||
<SkeletonLoader />
|
||||
);
|
||||
|
||||
if (isPending) return <SkeletonPostLoader />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="ql-snow">
|
||||
<Container size={"2"} className="mt-4">
|
||||
<Text className="mb-2" as="div" size={"9"}>{data.title}</Text>
|
||||
<Flex direction={"column"}>
|
||||
<Text className="mb-2" as="div" size={"9"}>
|
||||
{data.title}
|
||||
</Text>
|
||||
<Flex className="mt-4 mb-2">
|
||||
<div hidden={data.user_id != user?.id}>
|
||||
<ChangePostButton
|
||||
postId={queryParams["postId"] || ""}
|
||||
/>
|
||||
</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Separator size={"4"} className="mb-2" />
|
||||
<Interweave content={data.content} />
|
||||
</Container>
|
||||
|
||||
@ -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 (
|
||||
<Button
|
||||
size={"1"}
|
||||
className="h-5"
|
||||
variant="surface"
|
||||
onClick={() => navigate("/posts/change/" + props.postId)}
|
||||
>
|
||||
{"Change article"}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@ -5,7 +5,7 @@ import {
|
||||
pText,
|
||||
} from "../../../constants/textForSkeleton";
|
||||
|
||||
export default function SkeletonLoader() {
|
||||
export default function SkeletonPostLoader() {
|
||||
return (
|
||||
<Container size={"2"} className="mt-4">
|
||||
<Skeleton>
|
||||
|
||||
@ -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<Quill | null>(null);
|
||||
const [value, setValue] = useState(new Delta())
|
||||
const [value, setValue] = useState(new Delta());
|
||||
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (editor.current) {
|
||||
@ -50,25 +47,41 @@ const Editor = forwardRef((props: TEditor) => {
|
||||
};
|
||||
}, [editor.current]);
|
||||
|
||||
useEffect(() => {
|
||||
const quill = new Quill(document.createElement("div"));
|
||||
const t = quill.clipboard.convert({
|
||||
html: props.defaultValue as string,
|
||||
}) as Delta;
|
||||
|
||||
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())
|
||||
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 || "");
|
||||
if (loaded) setValue(fullDelta || new Delta());
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="text-editor">
|
||||
<ReactQuill
|
||||
value={value}
|
||||
ref={editor}
|
||||
modules={modules}
|
||||
|
||||
onChange={changeHandler}
|
||||
|
||||
|
||||
theme="snow"
|
||||
placeholder="Type your thoughts here..."
|
||||
/>
|
||||
|
||||
@ -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,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -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 (
|
||||
<>
|
||||
<Box className="flex flex-col flex-1">
|
||||
<Flex gap={"4"} direction={"column"} className="flex-[1]">
|
||||
<Container className="flex-[1]">
|
||||
<input
|
||||
disabled={isPending}
|
||||
placeholder={"Post title"}
|
||||
className="mb-2 border-0 border-b-[1px]
|
||||
outline-none w-full border-b-gray-400
|
||||
text-[60px] pl-4 pr-4 font-times"
|
||||
onChange={(e) => {
|
||||
setTitleValue(e.target.value);
|
||||
}}
|
||||
value={titleValue}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
<Container className="overflow-y-auto flex-grow-[100]">
|
||||
{isPending ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<Editor
|
||||
defaultValue={contentValue}
|
||||
onChange={setContentValue}
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
|
||||
<Box className="flex justify-center flex-[1] mb-4">
|
||||
<SubmitChangesButton
|
||||
contentValue={contentValue}
|
||||
titleValue={titleValue}
|
||||
className="text-2xl rounded-full w-52" />
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -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 === "<p><br></p>")
|
||||
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 (
|
||||
<Button
|
||||
onClick={() => {
|
||||
postMutation.mutate();
|
||||
}}
|
||||
className={props.className}
|
||||
variant="soft"
|
||||
size={"4"}
|
||||
disabled={isDisabled}
|
||||
>
|
||||
{t("updatePost")}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@ -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,
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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(
|
||||
/>
|
||||
|
||||
<Route path="/posts/:postId" element={<ArticleViewer />} />
|
||||
<Route path="/posts/change/:postId" element={<PostRedactor />} />
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
|
||||
@ -68,6 +68,6 @@ func Login(c *gin.Context) {
|
||||
|
||||
c.Header("Authorization", token)
|
||||
c.SetCookie(cookieName, cookieValue, maxAge, path, domain, secure, httpOnly)
|
||||
c.IndentedJSON(http.StatusOK, gin.H{"token": token, "username": user.Username})
|
||||
c.IndentedJSON(http.StatusOK, gin.H{"token": token, "username": user.Username, "id": user.UserID})
|
||||
|
||||
}
|
||||
|
||||
@ -119,5 +119,5 @@ func RegisterUser(c *gin.Context) {
|
||||
|
||||
transaction.Commit(context.Background())
|
||||
rest_api_stuff.SetCookie(c, cookieParams)
|
||||
c.IndentedJSON(http.StatusOK, gin.H{"status": "All good", "username": userParams.Username})
|
||||
c.IndentedJSON(http.StatusOK, gin.H{"status": "All good", "username": userParams.Username, "id": userParams.UserID})
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ func testAuth(c *gin.Context) {
|
||||
"message": "you are logged in, congrats!",
|
||||
"username": userInfo.Username,
|
||||
"is_admin": userInfo.IsAdmin,
|
||||
"id": userInfo.Id,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user