mirror of
https://github.com/lukevella/rallly.git
synced 2025-06-03 19:21:51 +02:00
Sessions (#162)
This commit is contained in:
parent
1d7bcddf1b
commit
5c991d7011
83 changed files with 2463 additions and 1178 deletions
|
@ -13,6 +13,7 @@ import {
|
|||
CreateCommentPayload,
|
||||
} from "../../api-client/create-comment";
|
||||
import { requiredString } from "../../utils/form-validation";
|
||||
import Badge from "../badge";
|
||||
import Button from "../button";
|
||||
import CompactButton from "../compact-button";
|
||||
import Dropdown, { DropdownItem } from "../dropdown";
|
||||
|
@ -20,13 +21,13 @@ import DotsHorizontal from "../icons/dots-horizontal.svg";
|
|||
import Trash from "../icons/trash.svg";
|
||||
import NameInput from "../name-input";
|
||||
import TruncatedLinkify from "../poll/truncated-linkify";
|
||||
import UserAvater from "../poll/user-avatar";
|
||||
import UserAvatar from "../poll/user-avatar";
|
||||
import { usePoll } from "../poll-context";
|
||||
import { usePreferences } from "../preferences/use-preferences";
|
||||
import { useUserName } from "../user-name-context";
|
||||
import { useSession } from "../session";
|
||||
|
||||
export interface DiscussionProps {
|
||||
pollId: string;
|
||||
canDelete?: boolean;
|
||||
}
|
||||
|
||||
interface CommentForm {
|
||||
|
@ -36,11 +37,9 @@ interface CommentForm {
|
|||
|
||||
const Discussion: React.VoidFunctionComponent<DiscussionProps> = ({
|
||||
pollId,
|
||||
canDelete,
|
||||
}) => {
|
||||
const { locale } = usePreferences();
|
||||
const getCommentsQueryKey = ["poll", pollId, "comments"];
|
||||
const [userName, setUserName] = useUserName();
|
||||
const queryClient = useQueryClient();
|
||||
const { data: comments } = useQuery(
|
||||
getCommentsQueryKey,
|
||||
|
@ -64,6 +63,7 @@ const Discussion: React.VoidFunctionComponent<DiscussionProps> = ({
|
|||
},
|
||||
{
|
||||
onSuccess: (newComment) => {
|
||||
session.refresh();
|
||||
queryClient.setQueryData(getCommentsQueryKey, (comments) => {
|
||||
if (Array.isArray(comments)) {
|
||||
return [...comments, newComment];
|
||||
|
@ -75,6 +75,8 @@ const Discussion: React.VoidFunctionComponent<DiscussionProps> = ({
|
|||
},
|
||||
);
|
||||
|
||||
const { poll } = usePoll();
|
||||
|
||||
const { mutate: deleteCommentMutation } = useMutation(
|
||||
async (payload: { pollId: string; commentId: string }) => {
|
||||
await axios.delete(`/api/poll/${pollId}/comments/${payload.commentId}`);
|
||||
|
@ -89,18 +91,16 @@ const Discussion: React.VoidFunctionComponent<DiscussionProps> = ({
|
|||
},
|
||||
);
|
||||
|
||||
const session = useSession();
|
||||
|
||||
const { register, setValue, control, handleSubmit, formState } =
|
||||
useForm<CommentForm>({
|
||||
defaultValues: {
|
||||
authorName: userName,
|
||||
authorName: "",
|
||||
content: "",
|
||||
},
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
setValue("authorName", userName);
|
||||
}, [setValue, userName]);
|
||||
|
||||
const handleDelete = React.useCallback(
|
||||
(commentId: string) => {
|
||||
deleteCommentMutation({ pollId, commentId });
|
||||
|
@ -124,6 +124,9 @@ const Discussion: React.VoidFunctionComponent<DiscussionProps> = ({
|
|||
>
|
||||
<AnimatePresence initial={false}>
|
||||
{comments.map((comment) => {
|
||||
const canDelete =
|
||||
poll.role === "admin" || session.ownsObject(comment);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
transition={{ duration: 0.2 }}
|
||||
|
@ -137,12 +140,16 @@ const Discussion: React.VoidFunctionComponent<DiscussionProps> = ({
|
|||
initial={{ scale: 0.8, y: 10 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.8 }}
|
||||
data-testid="comment"
|
||||
className="w-fit rounded-xl border bg-white px-3 py-2 shadow-sm"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<UserAvater name={comment.authorName} />
|
||||
<UserAvatar
|
||||
name={comment.authorName}
|
||||
showName={true}
|
||||
isYou={session.ownsObject(comment)}
|
||||
/>
|
||||
<div className="mb-1">
|
||||
<span className="mr-1">{comment.authorName}</span>
|
||||
<span className="mr-1 text-slate-400">•</span>
|
||||
<span className="text-sm text-slate-500">
|
||||
{formatRelative(
|
||||
|
@ -189,7 +196,6 @@ const Discussion: React.VoidFunctionComponent<DiscussionProps> = ({
|
|||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
setUserName(data.authorName);
|
||||
setValue("content", "");
|
||||
resolve(data);
|
||||
},
|
||||
|
@ -201,23 +207,28 @@ const Discussion: React.VoidFunctionComponent<DiscussionProps> = ({
|
|||
>
|
||||
<textarea
|
||||
id="comment"
|
||||
placeholder="Add your comment…"
|
||||
placeholder="Thanks for the invite!"
|
||||
className="input w-full py-2 pl-3 pr-4"
|
||||
{...register("content", { validate: requiredString })}
|
||||
/>
|
||||
<div className="mt-1 flex space-x-3">
|
||||
<Controller
|
||||
name="authorName"
|
||||
control={control}
|
||||
rules={{ validate: requiredString }}
|
||||
render={({ field }) => <NameInput className="w-full" {...field} />}
|
||||
/>
|
||||
<div>
|
||||
<Controller
|
||||
name="authorName"
|
||||
key={session.user?.id}
|
||||
control={control}
|
||||
rules={{ validate: requiredString }}
|
||||
render={({ field }) => (
|
||||
<NameInput {...field} className="w-full" />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
htmlType="submit"
|
||||
loading={formState.isSubmitting}
|
||||
type="primary"
|
||||
>
|
||||
Send
|
||||
Comment
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue