Blog creation and filling dialog completed #1

Merged
neki merged 10 commits from feature/blogCreationAndFilling into develop 2025-02-01 09:10:18 +00:00
5 changed files with 70 additions and 26 deletions
Showing only changes of commit fe311b9863 - Show all commits

View File

@ -1,7 +1,7 @@
{
"name": "enshi",
"private": true,
"version": "0.1.7",
"version": "0.1.8",
"type": "module",
"scripts": {
"dev": "vite",

View File

@ -13,7 +13,7 @@ const router = createBrowserRouter(routes);
export default function App() {
return (
<Theme className="h-fit" accentColor="indigo" grayColor="slate" appearance="dark">
<Theme className="h-fit" accentColor="sky" grayColor="slate" appearance="dark">
<ToastProvider>
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />

View File

@ -1,7 +1,10 @@
import { DoubleArrowDownIcon, DoubleArrowUpIcon } from "@radix-ui/react-icons";
import { IconButton } from "@radix-ui/themes";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useAtomValue } from "jotai";
import { axiosLocalhost } from "../../../api/axios/axios";
import { userAtom } from "../../../AtomStore/AtomStore";
import useToast from "../../../hooks/useToast";
export const UPVOTE = true;
export const DOWNVOTE = false;
@ -14,6 +17,9 @@ type TVoteButton = {
export default function VoteButton(props: TVoteButton) {
const queryClient = useQueryClient();
const user = useAtomValue(userAtom);
const createToast = useToast();
const { data } = useQuery({
queryKey: [props.vote + "voteCheck"],
queryFn: async () => {
@ -57,7 +63,13 @@ export default function VoteButton(props: TVoteButton) {
<IconButton
variant={data ? "solid" : "outline"}
size={"1"}
onClick={() => voteMutation.mutate()}
onClick={() => {
if(!user) {
createToast({title: "Please log in to vote", description: "You need to be logged in to vote on a post."});
return;
}
voteMutation.mutate();
}}
>
{props.vote ? <DoubleArrowUpIcon /> : <DoubleArrowDownIcon />}
</IconButton>

View File

@ -4,7 +4,7 @@ import { Button, Card, Flex, Select, Text, Theme } from "@radix-ui/themes";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useAtomValue } from "jotai";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useNavigate, useParams } from "react-router-dom";
import { Blog } from "../../../@types/BlogTypes";
import { axiosLocalhost } from "../../../api/axios/axios";
import { userAtom } from "../../../AtomStore/AtomStore";
@ -17,9 +17,12 @@ export default function AddPostToBlogDialog() {
const user = useAtomValue(userAtom);
const [selectedBlog, setSelectedBlog] = useState<string>("");
const createToast = useToast()
const [isOpen, setIsOpen] = useState(false);
const { data } = useQuery({
const params = useParams();
const createToast = useToast();
const { data, refetch } = useQuery({
queryKey: ["userBlogs"],
queryFn: async () => {
const response = await axiosLocalhost.get("/user/blogs", {
@ -30,20 +33,30 @@ export default function AddPostToBlogDialog() {
return temp as Blog[];
},
enabled: false,
});
const addMutation = useMutation({
mutationKey: ["addPostToBlog"],
mutationFn: async () => {
const response = await axiosLocalhost.put(
`posts/${params["postId"]}/blogs/${selectedBlog}`
);
return response.data;
},
onError: (error) => {
console.error(error);
createToast({title: "Error!", description: "Post have not been added"})
createToast({
title: "Error!",
description: "Post have not been added",
});
},
onSuccess: () => {
console.log("Post added successfully");
createToast({title: "Success!", description: "Post added successfully"})
createToast({
title: "Success!",
description: "Post added successfully",
});
},
onSettled: () => {
console.log("Add mutation is settled");
@ -56,7 +69,15 @@ export default function AddPostToBlogDialog() {
}
return (
<Dialog.Root>
<Dialog.Root
open={isOpen}
onOpenChange={(e) => {
setIsOpen(e);
if (e) {
refetch();
}
}}
>
<Dialog.Trigger asChild>
<Button variant="surface" className="h-5">
<Text>Add to blog</Text>
@ -64,9 +85,9 @@ export default function AddPostToBlogDialog() {
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 bg-black/40 data-[state=open]:animate-overlayShow" />
<Dialog.Content className="fixed left-1/2 top-1/2 max-h-[85vh] w-[90vw] max-w-[600px] -translate-x-1/2 -translate-y-1/2 rounded-md p-[25px] shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none data-[state=open]:animate-contentShow">
<Theme>
<Card>
<Dialog.Content className="fixed left-1/2 top-1/2 max-h-[85vh] w-[90vw] max-w-[600px] -translate-x-1/2 -translate-y-1/2 rounded-md shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none data-[state=open]:animate-contentShow">
<Theme panelBackground="solid">
<Card className="p-5">
<Dialog.Title className="m-0 text-[17px] font-medium text-mauve12">
<Text size={"4"}>Add this post to blog</Text>
</Dialog.Title>
@ -75,9 +96,9 @@ export default function AddPostToBlogDialog() {
<Text>{`Add post to `}</Text>
<Select.Root
value={selectedBlog}
onValueChange={(e) =>
setSelectedBlog(e)
}
onValueChange={(e) => {
setSelectedBlog(e);
}}
>
<Select.Trigger className="w-40 cursor-pointer" />
<Select.Content>
@ -98,15 +119,25 @@ export default function AddPostToBlogDialog() {
</Flex>
</Dialog.Description>
<div className="mt-[25px] flex justify-end">
<Dialog.Close asChild>
<Button
className="cursor-pointer"
>
<Text>Confirm</Text>
</Button>
</Dialog.Close>
</div>
<Flex
className="items-center justify-between"
>
{selectedBlog ? <div/> : <Text color="gray">* Please select a blog to attach the post to.</Text>}
<div className="flex flex-col justify-center">
<Dialog.Close asChild>
<Button
className="cursor-pointer"
onClick={() => {
addMutation.mutate();
}}
disabled={!selectedBlog}
>
<Text>Confirm</Text>
</Button>
</Dialog.Close>
</div>
</Flex>
<Dialog.Close asChild>
<button
className="absolute right-2.5 top-2.5 inline-flex size-[25px] appearance-none items-center justify-center rounded-full text-violet11 hover:bg-violet4 focus:shadow-[0_0_0_2px] focus:shadow-violet7 focus:outline-none"

View File

@ -10,7 +10,8 @@ export default function AuthPageWrapper(props: React.PropsWithChildren) {
const navigate = useNavigate();
if (!user) {
navigate("/login");
navigate("/login", { replace: true });
return (
<Container size={"4"} className="mt-4">
<Text size={"7"}>{t("errors.unauthorized")}</Text>