Skip to content

Commit

Permalink
feat: edit comments UI
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoEscaleira committed Mar 20, 2024
1 parent e17ea14 commit 964f19e
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 66 deletions.
5 changes: 5 additions & 0 deletions src/__generated__/gql.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/__generated__/graphql.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

126 changes: 126 additions & 0 deletions src/components/QuizComments/Comment.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { useState } from "react";
import { useMutation } from "@apollo/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { List, Button, Popover, PopoverContent, PopoverHandler, Textarea, Typography } from "@material-tailwind/react";
import { format } from "date-fns";
import { MoreHorizontal, User } from "lucide-react";
import { SubmitHandler, useForm } from "react-hook-form";
import { toast } from "react-toastify";
import { z } from "zod";
import { CommentDeleteDialog } from "@components/CommentDeleteDialog/CommentDeleteDialog";
import { QuizCommentsQuery } from "@generated/graphql";
import { useUserStore } from "@state/userStore";
import { GET_QUIZ_COMMENTS } from "@utils/queries/QuizComments";
import { UPDATE_QUIZ_COMMENT } from "@utils/queries/UpdateComment";
import { quizCommentFormSchema } from "./utils";

interface CommentProps {
comment: QuizCommentsQuery["quizComments"][0];
}

export const Comment = ({
comment: {
id: commentId,
text,
createdAt,
user: { id: commentUserId, firstName, lastName },
},
}: CommentProps) => {
const [isEditingId, setIsEditingId] = useState("");
const {
user: { userId },
} = useUserStore();

const [updateComment, { loading: loadingUpdateComment }] = useMutation(UPDATE_QUIZ_COMMENT, {
onCompleted: () => {
setIsEditingId("");
toast.success("Comment updated successfully!");
},
refetchQueries: [GET_QUIZ_COMMENTS],
});

const form = useForm<z.infer<typeof quizCommentFormSchema>>({
resolver: zodResolver(quizCommentFormSchema),
defaultValues: {
text: "",
},
});
const {
register,
handleSubmit,
formState: { errors },
} = form;

const onSubmit: SubmitHandler<z.infer<typeof quizCommentFormSchema>> = async (values, event) => {
event?.preventDefault();
try {
updateComment({ variables: { commentId: isEditingId, text: values.text } });
form.reset();
} catch (e) {
console.log("Something went wrong", e);
}
};

return (
<div key={commentId} className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<div className="flex items-center">
<User className="mr-2 size-4" />
<Typography className="font-medium">
{firstName}&nbsp;
{lastName}
</Typography>
<Typography variant="small" className="ml-2 opacity-70">
{format(new Date(createdAt), "dd MMM yyyy")}
</Typography>
</div>

{commentUserId === userId && (
<Popover>
<PopoverHandler>
<MoreHorizontal className="size-5 opacity-80 hover:cursor-pointer" />
</PopoverHandler>
<PopoverContent className="p-0">
<List>
<Button
variant="text"
color="gray"
className="outline-none"
onClick={() => {
setIsEditingId(commentId);
form.reset({ text });
}}
>
Edit
</Button>

<CommentDeleteDialog commentId={commentId} />
</List>
</PopoverContent>
</Popover>
)}
</div>

{isEditingId ? (
<form onSubmit={handleSubmit(onSubmit)} className="mt-2">
<Textarea {...register("text")} size="lg" label="Comment" error={!!errors.text} />
<div className=" mt-2 flex items-center gap-4">
<Button
color="blue"
type="submit"
loading={loadingUpdateComment}
disabled={loadingUpdateComment || !form.formState.isDirty}
>
Update
</Button>
<Button color="gray" variant="outlined" type="reset" onClick={() => setIsEditingId("")}>
Cancel
</Button>
</div>
</form>
) : (
<Typography className="whitespace-pre-line">{text}</Typography>
)}
</div>
);
};
84 changes: 19 additions & 65 deletions src/components/QuizComments/QuizComments.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
import { useMutation, useQuery } from "@apollo/client";
import { zodResolver } from "@hookform/resolvers/zod";
import {
Button,
Card,
CardBody,
CardHeader,
List,
Popover,
PopoverContent,
PopoverHandler,
Textarea,
Typography,
} from "@material-tailwind/react";
import { format } from "date-fns";
import { Loader2, User, MoreHorizontal } from "lucide-react";
import { Button, Card, CardBody, CardHeader, Textarea, Typography } from "@material-tailwind/react";
import { Loader2 } from "lucide-react";
import { SubmitHandler, useForm } from "react-hook-form";
import { useParams } from "react-router-dom";
import { z } from "zod";
import { CommentDeleteDialog } from "@components/CommentDeleteDialog/CommentDeleteDialog";
import { useUserStore } from "@state/userStore.ts";
import { CREATE_QUIZ_COMMENT } from "@utils/queries/CreateComment";
import { GET_QUIZ_COMMENTS } from "@utils/queries/QuizComments";

const quizCommentFormSchema = z.object({
text: z.string().min(5, { message: "Enter a comment." }),
});
import { Comment } from "./Comment";
import { quizCommentFormSchema } from "./utils";

export function QuizComments() {
const { quizId } = useParams();
Expand Down Expand Up @@ -72,57 +57,26 @@ export function QuizComments() {
</Typography>
</CardHeader>
<CardBody>
<form onSubmit={handleSubmit(onSubmit)}>
<Textarea {...register("text")} size="lg" label="Comment" error={!!errors.text} />
<Button
color="blue"
type="submit"
loading={loadingCreateComment}
disabled={loadingCreateComment || !form.formState.isDirty}
className="mt-2"
>
Post a comment
</Button>
</form>
{userId && (
<form onSubmit={handleSubmit(onSubmit)}>
<Textarea {...register("text")} size="lg" label="Comment" error={!!errors.text} />
<Button
color="blue"
type="submit"
loading={loadingCreateComment}
disabled={loadingCreateComment || !form.formState.isDirty}
className="mt-2"
>
Post a comment
</Button>
</form>
)}

<section className="mt-6 flex flex-col gap-6">
{loading ? (
<Loader2 size={24} className="animate-spin" />
) : (
comments.map(({ id: commentId, text, createdAt, user: { id: commentUserId, firstName, lastName } }) => (
<div key={commentId} className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<div className="flex items-center">
<User className="mr-2 size-4" />
<Typography className="font-medium">
{firstName}&nbsp;
{lastName}
</Typography>
<Typography variant="small" className="ml-2 opacity-70">
{format(new Date(createdAt), "dd MMM yyyy")}
</Typography>
</div>

{commentUserId === userId && (
<Popover>
<PopoverHandler>
<MoreHorizontal className="size-5 opacity-80 hover:cursor-pointer" />
</PopoverHandler>
<PopoverContent className="p-0">
<List>
<Button variant="text" color="gray" className="outline-none">
Edit
</Button>

<CommentDeleteDialog commentId={commentId} />
</List>
</PopoverContent>
</Popover>
)}
</div>
<Typography className="whitespace-pre-line">{text}</Typography>
</div>
))
comments.map(comment => <Comment key={comment.id} comment={comment} />)
)}
</section>
</CardBody>
Expand Down
5 changes: 5 additions & 0 deletions src/components/QuizComments/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { z } from "zod";

export const quizCommentFormSchema = z.object({
text: z.string().min(5, { message: "Enter a comment." }),
});
2 changes: 1 addition & 1 deletion src/pages/Game/CountryInfoModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const CountryInfoModal = ({
View country
</Button>
</Tooltip>
<Dialog open={isOpen} handler={toggleDialog}>
<Dialog open={isOpen} handler={toggleDialog} size="xs">
<DialogHeader>
<img src={flags.svg} alt={name} className="mr-3 size-5 rounded-full object-cover" />
{name}
Expand Down
7 changes: 7 additions & 0 deletions src/utils/queries/UpdateComment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { gql } from "@generated/gql.ts";

export const UPDATE_QUIZ_COMMENT = gql(/* GraphQL */ `
mutation UpdateQuizComments($commentId: String!, $text: String!) {
editComment(commentId: $commentId, text: $text)
}
`);

0 comments on commit 964f19e

Please sign in to comment.