mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: commenting issues fixed
This commit is contained in:
parent
4fd7a78d70
commit
376da835ba
@ -56,15 +56,18 @@ export const IssueListBlock: FC<{ issue: IIssue }> = observer((props) => {
|
||||
</div>
|
||||
|
||||
<div className="inline-flex flex-shrink-0 items-center gap-2 text-xs">
|
||||
{/* upvotes */}
|
||||
<div className="flex-shrink-0">
|
||||
<IssueBlockUpVotes number={totalUpVotes.length} />
|
||||
</div>
|
||||
|
||||
{/* downotes */}
|
||||
<div className="flex-shrink-0">
|
||||
<IssueBlockDownVotes number={totalDownVotes.length} />
|
||||
</div>
|
||||
{projectStore.deploySettings?.votes && (
|
||||
<>
|
||||
{/* upvotes */}
|
||||
<div className="flex-shrink-0">
|
||||
<IssueBlockUpVotes number={totalUpVotes.length} />
|
||||
</div>
|
||||
{/* downotes */}
|
||||
<div className="flex-shrink-0">
|
||||
<IssueBlockDownVotes number={totalDownVotes.length} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* priority */}
|
||||
{issue?.priority && (
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { useEffect } from "react";
|
||||
import Image from "next/image";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useRouter } from "next/router";
|
||||
// components
|
||||
import { NavbarSearch } from "./search";
|
||||
import { NavbarIssueBoardView } from "./issue-board-view";
|
||||
import { NavbarIssueFilter } from "./issue-filter";
|
||||
import { NavbarTheme } from "./theme";
|
||||
// mobx react lite
|
||||
import { observer } from "mobx-react-lite";
|
||||
// mobx
|
||||
// lib
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// store
|
||||
import { RootStore } from "store/root";
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const renderEmoji = (emoji: string | { name: string; color: string }) => {
|
||||
if (!emoji) return;
|
||||
@ -39,7 +39,6 @@ const IssueNavbar = observer(() => {
|
||||
useEffect(() => {
|
||||
if (workspace_slug && projectStore) {
|
||||
if (board) {
|
||||
console.log("setting");
|
||||
projectStore.setActiveBoard(board.toString());
|
||||
} else {
|
||||
router.push(`/${workspace_slug}/${project_slug}?board=list`);
|
||||
|
@ -1,22 +1,16 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
|
||||
// react-hook-form
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
// mobx
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
|
||||
// headless ui
|
||||
import { Menu, Transition } from "@headlessui/react";
|
||||
|
||||
// lib
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// icons
|
||||
import { ChatBubbleLeftEllipsisIcon, CheckIcon, XMarkIcon, EllipsisVerticalIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
// helpers
|
||||
import { timeAgo } from "helpers/date-time.helper";
|
||||
// types
|
||||
import { Comment } from "types";
|
||||
// components
|
||||
import { TipTapEditor } from "components/tiptap";
|
||||
|
||||
type Props = {
|
||||
@ -26,51 +20,37 @@ type Props = {
|
||||
|
||||
export const CommentCard: React.FC<Props> = observer((props) => {
|
||||
const { comment, workspaceSlug } = props;
|
||||
|
||||
const { user: userStore, issue: issueStore } = useMobxStore();
|
||||
|
||||
const editorRef = useRef<any>(null);
|
||||
const showEditorRef = useRef<any>(null);
|
||||
|
||||
// store
|
||||
const { user: userStore, issue: issueStore, issueDetails: issueDetailStore } = useMobxStore();
|
||||
// states
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
|
||||
const {
|
||||
formState: { isSubmitting },
|
||||
handleSubmit,
|
||||
setFocus,
|
||||
watch,
|
||||
setValue,
|
||||
} = useForm<Comment>({
|
||||
defaultValues: comment,
|
||||
control,
|
||||
} = useForm<any>({
|
||||
defaultValues: { comment_html: comment.comment_html },
|
||||
});
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (!workspaceSlug || !issueStore.activePeekOverviewIssueId) return;
|
||||
if (!workspaceSlug || !issueDetailStore.peekId) return;
|
||||
|
||||
await issueStore.deleteIssueCommentAsync(
|
||||
workspaceSlug,
|
||||
comment.project,
|
||||
issueStore.activePeekOverviewIssueId,
|
||||
comment.id
|
||||
);
|
||||
await issueDetailStore.deleteIssueComment(workspaceSlug, comment.project, issueDetailStore.peekId, comment.id);
|
||||
};
|
||||
|
||||
const handleCommentUpdate = async (formData: Comment) => {
|
||||
if (!workspaceSlug || !issueStore.activePeekOverviewIssueId) return;
|
||||
if (!workspaceSlug || !issueDetailStore.peekId) return;
|
||||
|
||||
const response = await issueStore.updateIssueCommentAsync(
|
||||
console.log("formData", formData);
|
||||
const response = await issueDetailStore.updateIssueComment(
|
||||
workspaceSlug,
|
||||
comment.project,
|
||||
issueStore.activePeekOverviewIssueId,
|
||||
issueDetailStore.peekId,
|
||||
comment.id,
|
||||
formData
|
||||
);
|
||||
|
||||
if (response) {
|
||||
editorRef.current?.setEditorValue(response.comment_html);
|
||||
showEditorRef.current?.setEditorValue(response.comment_html);
|
||||
}
|
||||
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
@ -82,6 +62,7 @@ export const CommentCard: React.FC<Props> = observer((props) => {
|
||||
<div className="relative flex items-start space-x-3">
|
||||
<div className="relative px-1">
|
||||
{comment.actor_detail.avatar && comment.actor_detail.avatar !== "" ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={comment.actor_detail.avatar}
|
||||
alt={
|
||||
@ -118,16 +99,20 @@ export const CommentCard: React.FC<Props> = observer((props) => {
|
||||
className={`flex-col gap-2 ${isEditing ? "flex" : "hidden"}`}
|
||||
>
|
||||
<div>
|
||||
<TipTapEditor
|
||||
workspaceSlug={workspaceSlug as string}
|
||||
ref={editorRef}
|
||||
value={watch("comment_html")}
|
||||
debouncedUpdatesEnabled={false}
|
||||
customClassName="min-h-[50px] p-3 shadow-sm"
|
||||
onChange={(comment_json: Object, comment_html: string) => {
|
||||
setValue("comment_json", comment_json);
|
||||
setValue("comment_html", comment_html);
|
||||
}}
|
||||
<Controller
|
||||
control={control}
|
||||
name="comment_html"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TipTapEditor
|
||||
workspaceSlug={workspaceSlug as string}
|
||||
value={value}
|
||||
debouncedUpdatesEnabled={false}
|
||||
customClassName="min-h-[50px] p-3 shadow-sm"
|
||||
onChange={(comment_json: Object, comment_html: string) => {
|
||||
onChange(comment_html);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-1 self-end">
|
||||
@ -149,8 +134,7 @@ export const CommentCard: React.FC<Props> = observer((props) => {
|
||||
</form>
|
||||
<div className={`${isEditing ? "hidden" : ""}`}>
|
||||
<TipTapEditor
|
||||
workspaceSlug={workspaceSlug as string}
|
||||
ref={showEditorRef}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
value={comment.comment_html}
|
||||
editable={false}
|
||||
customClassName="text-xs border border-custom-border-200 bg-custom-background-100"
|
||||
|
@ -20,6 +20,8 @@ export const PeekOverviewIssueActivity: React.FC<Props> = observer((props) => {
|
||||
|
||||
const comments = issueDetailStore.details[issueDetailStore.peekId || ""]?.comments || [];
|
||||
|
||||
console.log("comments", comments);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h4 className="font-medium">Activity</h4>
|
||||
|
@ -19,7 +19,7 @@ export const IssuePeekOverview: React.FC<Props> = observer((props) => {
|
||||
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspace_slug, project_slug, peekId } = router.query;
|
||||
const { workspace_slug, project_slug, peekId, board } = router.query;
|
||||
// store
|
||||
const { issueDetails: issueDetailStore, issue: issueStore } = useMobxStore();
|
||||
|
||||
@ -34,14 +34,13 @@ export const IssuePeekOverview: React.FC<Props> = observer((props) => {
|
||||
}, [workspace_slug, project_slug, issueDetailStore, issueDetails, peekId, issueStore.issues]);
|
||||
|
||||
const handleClose = () => {
|
||||
const { query } = router;
|
||||
delete query.peekId;
|
||||
|
||||
issueDetailStore.setPeekId(null);
|
||||
router.replace(
|
||||
{
|
||||
pathname: `/${workspace_slug?.toString()}/${project_slug}`,
|
||||
query,
|
||||
query: {
|
||||
board,
|
||||
},
|
||||
},
|
||||
undefined,
|
||||
{ shallow: true }
|
||||
|
@ -30,7 +30,7 @@ export const SidePeekView: React.FC<Props> = observer((props) => {
|
||||
<PeekOverviewIssueDetails issueDetails={issueDetails} />
|
||||
</div>
|
||||
{/* issue properties */}
|
||||
<div className="w-full mt-10">
|
||||
<div className="w-full mt-6">
|
||||
<PeekOverviewIssueProperties issueDetails={issueDetails} />
|
||||
</div>
|
||||
{/* divider */}
|
||||
|
@ -38,7 +38,6 @@ const HomePage = () => {
|
||||
router.push(`/onboarding?next_path=${next_path}`);
|
||||
return;
|
||||
}
|
||||
console.log("hello");
|
||||
router.push(next_path.toString());
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
"tailwindcss/nesting": {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
|
@ -23,7 +23,14 @@ export interface IIssueDetailStore {
|
||||
fetchIssueDetails: (workspaceId: string, projectId: string, issueId: string) => void;
|
||||
// issue comments
|
||||
addIssueComment: (workspaceId: string, projectId: string, issueId: string, data: any) => Promise<void>;
|
||||
deleteIssueComment: (workspaceId: string, projectId: string, issueId: string) => void;
|
||||
updateIssueComment: (
|
||||
workspaceId: string,
|
||||
projectId: string,
|
||||
issueId: string,
|
||||
comment_id: string,
|
||||
data: any
|
||||
) => Promise<any>;
|
||||
deleteIssueComment: (workspaceId: string, projectId: string, issueId: string, comment_id: string) => void;
|
||||
// issue reactions
|
||||
addIssueReaction: (workspaceId: string, projectId: string, issueId: string, data: any) => void;
|
||||
removeIssueReaction: (workspaceId: string, projectId: string, issueId: string, data: any) => void;
|
||||
@ -40,7 +47,7 @@ class IssueDetailStore implements IssueDetailStore {
|
||||
details: {
|
||||
[key: string]: IIssue;
|
||||
} = {};
|
||||
issueService: any;
|
||||
issueService;
|
||||
rootStore: RootStore;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
@ -97,7 +104,6 @@ class IssueDetailStore implements IssueDetailStore {
|
||||
try {
|
||||
const issueDetails = this.rootStore.issue.issues?.find((i) => i.id === issueId);
|
||||
const issueCommentResponse = await this.issueService.createIssueComment(workspaceSlug, projectId, issueId, data);
|
||||
console.log("issueCommentResponse", issueCommentResponse);
|
||||
if (issueDetails) {
|
||||
runInAction(() => {
|
||||
this.details = {
|
||||
@ -116,36 +122,58 @@ class IssueDetailStore implements IssueDetailStore {
|
||||
}
|
||||
};
|
||||
|
||||
updateIssueComment = async (workspaceSlug: string, projectId: string, issueId: string, data: any) => {
|
||||
updateIssueComment = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
issueId: string,
|
||||
commentId: string,
|
||||
data: any
|
||||
) => {
|
||||
try {
|
||||
const issueVoteResponse = await this.issueService.updateIssueComment(workspaceSlug, projectId, issueId, data);
|
||||
if (issueVoteResponse) {
|
||||
const issueCommentUpdateResponse = await this.issueService.updateIssueComment(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
issueId,
|
||||
commentId,
|
||||
data
|
||||
);
|
||||
// const issueComments = await this.issueService.getIssueComments(workspaceSlug, projectId, issueId);
|
||||
|
||||
if (issueCommentUpdateResponse) {
|
||||
runInAction(() => {
|
||||
const remainingComments = this.details[issueId].comments.filter((com) => com.id === commentId);
|
||||
this.details = {
|
||||
...this.details,
|
||||
[issueId]: {
|
||||
...issueDetails,
|
||||
comments: commentsResponse,
|
||||
...this.details[issueId],
|
||||
comments: [...remainingComments, issueCommentUpdateResponse],
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
return issueCommentUpdateResponse;
|
||||
} catch (error) {
|
||||
console.log("Failed to add issue comment");
|
||||
}
|
||||
};
|
||||
|
||||
deleteIssueComment = async () => {
|
||||
deleteIssueComment = async (workspaceSlug: string, projectId: string, issueId: string, comment_id: string) => {
|
||||
try {
|
||||
const issueVoteResponse = await this.issueService.deleteIssueComment(workspaceSlug, projectId, issueId, data);
|
||||
// const issueDetails = await this.issueService.fetchIssueDetails(workspaceSlug, projectId, issueId);
|
||||
const issueVoteResponse = await this.issueService.deleteIssueComment(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
issueId,
|
||||
comment_id
|
||||
);
|
||||
const issueComments = await this.issueService.getIssueComments(workspaceSlug, projectId, issueId);
|
||||
|
||||
if (issueVoteResponse) {
|
||||
runInAction(() => {
|
||||
this.details = {
|
||||
...this.details,
|
||||
[issueId]: {
|
||||
...issueDetails,
|
||||
...this.details[issueId],
|
||||
comments: issueComments,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user