Some improvements here and there

This commit is contained in:
Max 2025-02-01 12:03:20 +03:00
parent 273bcf743f
commit fe311b9863
5 changed files with 70 additions and 26 deletions

View File

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

View File

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

View File

@ -1,7 +1,10 @@
import { DoubleArrowDownIcon, DoubleArrowUpIcon } from "@radix-ui/react-icons"; import { DoubleArrowDownIcon, DoubleArrowUpIcon } from "@radix-ui/react-icons";
import { IconButton } from "@radix-ui/themes"; import { IconButton } from "@radix-ui/themes";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useAtomValue } from "jotai";
import { axiosLocalhost } from "../../../api/axios/axios"; import { axiosLocalhost } from "../../../api/axios/axios";
import { userAtom } from "../../../AtomStore/AtomStore";
import useToast from "../../../hooks/useToast";
export const UPVOTE = true; export const UPVOTE = true;
export const DOWNVOTE = false; export const DOWNVOTE = false;
@ -14,6 +17,9 @@ type TVoteButton = {
export default function VoteButton(props: TVoteButton) { export default function VoteButton(props: TVoteButton) {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const user = useAtomValue(userAtom);
const createToast = useToast();
const { data } = useQuery({ const { data } = useQuery({
queryKey: [props.vote + "voteCheck"], queryKey: [props.vote + "voteCheck"],
queryFn: async () => { queryFn: async () => {
@ -57,7 +63,13 @@ export default function VoteButton(props: TVoteButton) {
<IconButton <IconButton
variant={data ? "solid" : "outline"} variant={data ? "solid" : "outline"}
size={"1"} 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 />} {props.vote ? <DoubleArrowUpIcon /> : <DoubleArrowDownIcon />}
</IconButton> </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 { useMutation, useQuery } from "@tanstack/react-query";
import { useAtomValue } from "jotai"; import { useAtomValue } from "jotai";
import { useState } from "react"; import { useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import { Blog } from "../../../@types/BlogTypes"; import { Blog } from "../../../@types/BlogTypes";
import { axiosLocalhost } from "../../../api/axios/axios"; import { axiosLocalhost } from "../../../api/axios/axios";
import { userAtom } from "../../../AtomStore/AtomStore"; import { userAtom } from "../../../AtomStore/AtomStore";
@ -17,9 +17,12 @@ export default function AddPostToBlogDialog() {
const user = useAtomValue(userAtom); const user = useAtomValue(userAtom);
const [selectedBlog, setSelectedBlog] = useState<string>(""); 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"], queryKey: ["userBlogs"],
queryFn: async () => { queryFn: async () => {
const response = await axiosLocalhost.get("/user/blogs", { const response = await axiosLocalhost.get("/user/blogs", {
@ -30,20 +33,30 @@ export default function AddPostToBlogDialog() {
return temp as Blog[]; return temp as Blog[];
}, },
enabled: false,
}); });
const addMutation = useMutation({ const addMutation = useMutation({
mutationKey: ["addPostToBlog"], mutationKey: ["addPostToBlog"],
mutationFn: async () => { mutationFn: async () => {
const response = await axiosLocalhost.put(
`posts/${params["postId"]}/blogs/${selectedBlog}`
);
return response.data;
}, },
onError: (error) => { onError: (error) => {
console.error(error); console.error(error);
createToast({title: "Error!", description: "Post have not been added"}) createToast({
title: "Error!",
description: "Post have not been added",
});
}, },
onSuccess: () => { onSuccess: () => {
console.log("Post added successfully"); console.log("Post added successfully");
createToast({title: "Success!", description: "Post added successfully"}) createToast({
title: "Success!",
description: "Post added successfully",
});
}, },
onSettled: () => { onSettled: () => {
console.log("Add mutation is settled"); console.log("Add mutation is settled");
@ -56,7 +69,15 @@ export default function AddPostToBlogDialog() {
} }
return ( return (
<Dialog.Root> <Dialog.Root
open={isOpen}
onOpenChange={(e) => {
setIsOpen(e);
if (e) {
refetch();
}
}}
>
<Dialog.Trigger asChild> <Dialog.Trigger asChild>
<Button variant="surface" className="h-5"> <Button variant="surface" className="h-5">
<Text>Add to blog</Text> <Text>Add to blog</Text>
@ -64,9 +85,9 @@ export default function AddPostToBlogDialog() {
</Dialog.Trigger> </Dialog.Trigger>
<Dialog.Portal> <Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 bg-black/40 data-[state=open]:animate-overlayShow" /> <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"> <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> <Theme panelBackground="solid">
<Card> <Card className="p-5">
<Dialog.Title className="m-0 text-[17px] font-medium text-mauve12"> <Dialog.Title className="m-0 text-[17px] font-medium text-mauve12">
<Text size={"4"}>Add this post to blog</Text> <Text size={"4"}>Add this post to blog</Text>
</Dialog.Title> </Dialog.Title>
@ -75,9 +96,9 @@ export default function AddPostToBlogDialog() {
<Text>{`Add post to `}</Text> <Text>{`Add post to `}</Text>
<Select.Root <Select.Root
value={selectedBlog} value={selectedBlog}
onValueChange={(e) => onValueChange={(e) => {
setSelectedBlog(e) setSelectedBlog(e);
} }}
> >
<Select.Trigger className="w-40 cursor-pointer" /> <Select.Trigger className="w-40 cursor-pointer" />
<Select.Content> <Select.Content>
@ -98,15 +119,25 @@ export default function AddPostToBlogDialog() {
</Flex> </Flex>
</Dialog.Description> </Dialog.Description>
<div className="mt-[25px] flex justify-end"> <Flex
<Dialog.Close asChild> className="items-center justify-between"
<Button >
className="cursor-pointer" {selectedBlog ? <div/> : <Text color="gray">* Please select a blog to attach the post to.</Text>}
>
<Text>Confirm</Text> <div className="flex flex-col justify-center">
</Button> <Dialog.Close asChild>
</Dialog.Close> <Button
</div> className="cursor-pointer"
onClick={() => {
addMutation.mutate();
}}
disabled={!selectedBlog}
>
<Text>Confirm</Text>
</Button>
</Dialog.Close>
</div>
</Flex>
<Dialog.Close asChild> <Dialog.Close asChild>
<button <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" 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(); const navigate = useNavigate();
if (!user) { if (!user) {
navigate("/login"); navigate("/login", { replace: true });
return ( return (
<Container size={"4"} className="mt-4"> <Container size={"4"} className="mt-4">
<Text size={"7"}>{t("errors.unauthorized")}</Text> <Text size={"7"}>{t("errors.unauthorized")}</Text>