|
|
|
@ -1,8 +1,14 @@
|
|
|
|
|
import { useState } from 'react';
|
|
|
|
|
import type { SubmitHandler } from 'react-hook-form';
|
|
|
|
|
import { useForm } from 'react-hook-form';
|
|
|
|
|
import {
|
|
|
|
|
ArrowDownCircleIcon,
|
|
|
|
|
ArrowUpCircleIcon,
|
|
|
|
|
} from '@heroicons/react/20/solid';
|
|
|
|
|
import { FaceSmileIcon } from '@heroicons/react/24/outline';
|
|
|
|
|
import { Button, TextArea } from '@tih/ui';
|
|
|
|
|
|
|
|
|
|
import { trpc } from '~/utils/trpc';
|
|
|
|
|
|
|
|
|
|
import ResumeExpandableText from '../shared/ResumeExpandableText';
|
|
|
|
|
|
|
|
|
@ -13,11 +19,63 @@ type ResumeCommentListItemProps = {
|
|
|
|
|
userId?: string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type ICommentInput = {
|
|
|
|
|
description: string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default function ResumeCommentListItem({
|
|
|
|
|
comment,
|
|
|
|
|
userId,
|
|
|
|
|
}: ResumeCommentListItemProps) {
|
|
|
|
|
const isCommentOwner = userId === comment.user.userId;
|
|
|
|
|
const [isEditingComment, setIsEditingComment] = useState(false);
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
register,
|
|
|
|
|
handleSubmit,
|
|
|
|
|
setValue,
|
|
|
|
|
formState: { errors, isDirty },
|
|
|
|
|
reset,
|
|
|
|
|
} = useForm<ICommentInput>({
|
|
|
|
|
defaultValues: {
|
|
|
|
|
description: comment.description,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const trpcContext = trpc.useContext();
|
|
|
|
|
const commentUpdateMutation = trpc.useMutation(
|
|
|
|
|
'resumes.comments.user.update',
|
|
|
|
|
{
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
// Comment updated, invalidate query to trigger refetch
|
|
|
|
|
trpcContext.invalidateQueries(['resumes.comments.list']);
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const onCancel = () => {
|
|
|
|
|
reset({ description: comment.description });
|
|
|
|
|
setIsEditingComment(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onSubmit: SubmitHandler<ICommentInput> = async (data) => {
|
|
|
|
|
const { id } = comment;
|
|
|
|
|
return await commentUpdateMutation.mutate(
|
|
|
|
|
{
|
|
|
|
|
id,
|
|
|
|
|
...data,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
setIsEditingComment(false);
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const setFormValue = (value: string) => {
|
|
|
|
|
setValue('description', value.trim(), { shouldDirty: true });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="border-primary-300 w-3/4 rounded-md border-2 bg-white p-2 drop-shadow-md">
|
|
|
|
@ -54,7 +112,45 @@ export default function ResumeCommentListItem({
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Description */}
|
|
|
|
|
<ResumeExpandableText text={comment.description} />
|
|
|
|
|
{isEditingComment ? (
|
|
|
|
|
<form onSubmit={handleSubmit(onSubmit)}>
|
|
|
|
|
<div className="flex-column mt-1 space-y-2">
|
|
|
|
|
<TextArea
|
|
|
|
|
{...(register('description', {
|
|
|
|
|
required: 'Comments cannot be empty!',
|
|
|
|
|
}),
|
|
|
|
|
{})}
|
|
|
|
|
defaultValue={comment.description}
|
|
|
|
|
disabled={commentUpdateMutation.isLoading}
|
|
|
|
|
errorMessage={errors.description?.message}
|
|
|
|
|
label="Edit comment"
|
|
|
|
|
placeholder="Leave your comment here"
|
|
|
|
|
onChange={setFormValue}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div className="flex-row space-x-2">
|
|
|
|
|
<Button
|
|
|
|
|
disabled={commentUpdateMutation.isLoading}
|
|
|
|
|
label="Cancel"
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="tertiary"
|
|
|
|
|
onClick={onCancel}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
disabled={!isDirty || commentUpdateMutation.isLoading}
|
|
|
|
|
isLoading={commentUpdateMutation.isLoading}
|
|
|
|
|
label="Confirm"
|
|
|
|
|
size="sm"
|
|
|
|
|
type="submit"
|
|
|
|
|
variant="primary"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
) : (
|
|
|
|
|
<ResumeExpandableText text={comment.description} />
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Upvote and edit */}
|
|
|
|
|
<div className="flex flex-row space-x-1 pt-1 align-middle">
|
|
|
|
@ -63,12 +159,14 @@ export default function ResumeCommentListItem({
|
|
|
|
|
<div className="text-xs">{comment.numVotes}</div>
|
|
|
|
|
<ArrowDownCircleIcon className="h-4 w-4 fill-gray-400" />
|
|
|
|
|
|
|
|
|
|
{/* TODO: Implement edit */}
|
|
|
|
|
{isCommentOwner ? (
|
|
|
|
|
<div className="text-primary-800 hover:text-primary-400 px-1 text-xs">
|
|
|
|
|
{isCommentOwner && !isEditingComment && (
|
|
|
|
|
<a
|
|
|
|
|
className="text-primary-800 hover:text-primary-400 px-1 text-xs"
|
|
|
|
|
href="#"
|
|
|
|
|
onClick={() => setIsEditingComment(true)}>
|
|
|
|
|
Edit
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
|
|
|
|
</a>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|