diff --git a/web/components/inbox/issue-activity.tsx b/web/components/inbox/issue-activity.tsx index 92013d3de..2b8fe7d9b 100644 --- a/web/components/inbox/issue-activity.tsx +++ b/web/components/inbox/issue-activity.tsx @@ -10,7 +10,7 @@ import { IssueService, IssueCommentService } from "services/issue"; // hooks import useToast from "hooks/use-toast"; // types -import { IIssue, IIssueComment } from "types"; +import { IIssue, IIssueActivity } from "types"; // fetch-keys import { PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys"; @@ -41,7 +41,7 @@ export const InboxIssueActivity: React.FC = observer(({ issueDetails }) = const user = userStore.currentUser; - const handleCommentUpdate = async (commentId: string, data: Partial) => { + const handleCommentUpdate = async (commentId: string, data: Partial) => { if (!workspaceSlug || !projectId || !issueDetails.id || !user) return; await issueCommentService @@ -86,7 +86,7 @@ export const InboxIssueActivity: React.FC = observer(({ issueDetails }) = }); }; - const handleAddComment = async (formData: IIssueComment) => { + const handleAddComment = async (formData: IIssueActivity) => { if (!workspaceSlug || !issueDetails || !user) return; await issueCommentService diff --git a/web/components/inbox/main-content.tsx b/web/components/inbox/main-content.tsx index e3b9aaca5..fc4ecaa4d 100644 --- a/web/components/inbox/main-content.tsx +++ b/web/components/inbox/main-content.tsx @@ -37,13 +37,10 @@ export const InboxMainContent: React.FC = observer(() => { const { inboxIssues: inboxIssuesStore, inboxIssueDetails: inboxIssueDetailsStore, - user: userStore, + user: { currentUser, currentProjectRole }, projectState: { states }, } = useMobxStore(); - const user = userStore.currentUser; - const userRole = userStore.currentProjectRole; - const { reset, control, watch } = useForm({ defaultValues, }); @@ -156,7 +153,7 @@ export const InboxMainContent: React.FC = observer(() => { ); - const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER; + const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; return ( <> @@ -249,12 +246,17 @@ export const InboxMainContent: React.FC = observer(() => { id: issueDetails.id, }} handleFormSubmit={submitChanges} - isAllowed={isAllowed || user?.id === issueDetails.created_by} + isAllowed={isAllowed || currentUser?.id === issueDetails.created_by} /> - - + {workspaceSlug && projectId && ( + + )} diff --git a/web/components/issues/activity.tsx b/web/components/issues/activity.tsx index dff64ba41..42b7972e4 100644 --- a/web/components/issues/activity.tsx +++ b/web/components/issues/activity.tsx @@ -11,12 +11,12 @@ import { Loader, Tooltip } from "@plane/ui"; // helpers import { render24HourFormatTime, renderLongDateFormat, timeAgo } from "helpers/date-time.helper"; // types -import { IIssueActivity, IIssueComment } from "types"; +import { IIssueActivity } from "types"; import { History } from "lucide-react"; type Props = { activity: IIssueActivity[] | undefined; - handleCommentUpdate: (commentId: string, data: Partial) => Promise; + handleCommentUpdate: (commentId: string, data: Partial) => Promise; handleCommentDelete: (commentId: string) => Promise; showAccessSpecifier?: boolean; }; @@ -130,7 +130,7 @@ export const IssueActivitySection: React.FC = ({ return (
= { +const defaultValues: Partial = { access: "INTERNAL", comment_html: "", }; type Props = { disabled?: boolean; - onSubmit: (data: IIssueComment) => Promise; + onSubmit: (data: IIssueActivity) => Promise; showAccessSpecifier?: boolean; }; @@ -59,9 +59,9 @@ export const AddComment: React.FC = ({ disabled = false, onSubmit, showAc formState: { isSubmitting }, handleSubmit, reset, - } = useForm({ defaultValues }); + } = useForm({ defaultValues }); - const handleAddComment = async (formData: IIssueComment) => { + const handleAddComment = async (formData: IIssueActivity) => { if (!formData.comment_html || isSubmitting) return; await onSubmit(formData).then(() => { @@ -96,7 +96,7 @@ export const AddComment: React.FC = ({ disabled = false, onSubmit, showAc onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)} commentAccessSpecifier={ showAccessSpecifier - ? { accessValue, onAccessChange, showAccessSpecifier, commentAccess } + ? { accessValue: accessValue ?? "INTERNAL", onAccessChange, showAccessSpecifier, commentAccess } : undefined } mentionSuggestions={editorSuggestions.mentionSuggestions} diff --git a/web/components/issues/comment/comment-card.tsx b/web/components/issues/comment/comment-card.tsx index 19fbd815d..376246e84 100644 --- a/web/components/issues/comment/comment-card.tsx +++ b/web/components/issues/comment/comment-card.tsx @@ -14,16 +14,16 @@ import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-te // helpers import { timeAgo } from "helpers/date-time.helper"; // types -import type { IIssueComment } from "types"; +import type { IIssueActivity } from "types"; import useEditorSuggestions from "hooks/use-editor-suggestions"; // services const fileService = new FileService(); type Props = { - comment: IIssueComment; + comment: IIssueActivity; handleCommentDeletion: (comment: string) => void; - onSubmit: (commentId: string, data: Partial) => void; + onSubmit: (commentId: string, data: Partial) => void; showAccessSpecifier?: boolean; workspaceSlug: string; }; @@ -50,11 +50,11 @@ export const CommentCard: React.FC = ({ setFocus, watch, setValue, - } = useForm({ + } = useForm({ defaultValues: comment, }); - const onEnter = (formData: Partial) => { + const onEnter = (formData: Partial) => { if (isSubmitting) return; setIsEditing(false); @@ -110,13 +110,10 @@ export const CommentCard: React.FC = ({ deleteFile={fileService.deleteImage} restoreFile={fileService.restoreImage} ref={editorRef} - value={watch("comment_html")} + 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); - }} + onChange={(comment_json: Object, comment_html: string) => setValue("comment_html", comment_html)} mentionSuggestions={editorSuggestions.mentionSuggestions} mentionHighlights={editorSuggestions.mentionHighlights} /> @@ -147,7 +144,7 @@ export const CommentCard: React.FC = ({ )} diff --git a/web/components/issues/draft-issue-modal.tsx b/web/components/issues/draft-issue-modal.tsx index e7ee23481..51ff30d40 100644 --- a/web/components/issues/draft-issue-modal.tsx +++ b/web/components/issues/draft-issue-modal.tsx @@ -6,7 +6,7 @@ import { Dialog, Transition } from "@headlessui/react"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // services -import { IssueService, IssueDraftService } from "services/issue"; +import { IssueService } from "services/issue"; import { ModuleService } from "services/module.service"; // hooks import useToast from "hooks/use-toast"; diff --git a/web/components/issues/index.ts b/web/components/issues/index.ts index f8f0ba003..53b873894 100644 --- a/web/components/issues/index.ts +++ b/web/components/issues/index.ts @@ -7,7 +7,7 @@ export * from "./delete-issue-modal"; export * from "./description-form"; export * from "./form"; export * from "./issue-layouts"; -export * from "./issue-peek-overview"; +export * from "./peek-overview"; export * from "./main-content"; export * from "./modal"; export * from "./parent-issues-list-modal"; diff --git a/web/components/issues/issue-layouts/calendar/base-calendar-root.tsx b/web/components/issues/issue-layouts/calendar/base-calendar-root.tsx index abdca8d55..e4aa079b5 100644 --- a/web/components/issues/issue-layouts/calendar/base-calendar-root.tsx +++ b/web/components/issues/issue-layouts/calendar/base-calendar-root.tsx @@ -31,9 +31,9 @@ interface IBaseCalendarRoot { calendarViewStore: IIssueCalendarViewStore; QuickActions: FC; issueActions: { - [EIssueActions.DELETE]: (issue: IIssue) => void; - [EIssueActions.UPDATE]?: (issue: IIssue) => void; - [EIssueActions.REMOVE]?: (issue: IIssue) => void; + [EIssueActions.DELETE]: (issue: IIssue) => Promise; + [EIssueActions.UPDATE]?: (issue: IIssue) => Promise; + [EIssueActions.REMOVE]?: (issue: IIssue) => Promise; }; viewId?: string; handleDragDrop: (source: any, destination: any, issues: any, issueWithIds: any) => void; @@ -64,9 +64,9 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => { }; const handleIssues = useCallback( - (date: string, issue: IIssue, action: EIssueActions) => { + async (date: string, issue: IIssue, action: EIssueActions) => { if (issueActions[action]) { - issueActions[action]!(issue); + await issueActions[action]!(issue); } }, [issueActions] @@ -108,8 +108,8 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => { workspaceSlug={workspaceSlug.toString()} projectId={peekProjectId.toString()} issueId={peekIssueId.toString()} - handleIssue={(issueToUpdate) => - handleIssues(issueToUpdate.target_date ?? "", issueToUpdate as IIssue, EIssueActions.UPDATE) + handleIssue={async (issueToUpdate) => + await handleIssues(issueToUpdate.target_date ?? "", issueToUpdate as IIssue, EIssueActions.UPDATE) } /> )} diff --git a/web/components/issues/issue-layouts/calendar/roots/cycle-root.tsx b/web/components/issues/issue-layouts/calendar/roots/cycle-root.tsx index fde701b51..784e9a830 100644 --- a/web/components/issues/issue-layouts/calendar/roots/cycle-root.tsx +++ b/web/components/issues/issue-layouts/calendar/roots/cycle-root.tsx @@ -14,46 +14,50 @@ export const CycleCalendarLayout: React.FC = observer(() => { cycleIssues: cycleIssueStore, cycleIssuesFilter: cycleIssueFilterStore, cycleIssueCalendarView: cycleIssueCalendarViewStore, - calendarHelpers: calendarHelperStore, + calendarHelpers: { handleDragDrop: handleCalenderDragDrop }, } = useMobxStore(); const router = useRouter(); - const { workspaceSlug, projectId, cycleId } = router.query as { - workspaceSlug: string; - projectId: string; - cycleId: string; - }; + const { workspaceSlug, projectId, cycleId } = router.query; const issueActions = { [EIssueActions.UPDATE]: async (issue: IIssue) => { if (!workspaceSlug || !cycleId) return; - cycleIssueStore.updateIssue(workspaceSlug, issue.project, issue.id, issue, cycleId); + await cycleIssueStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue, cycleId.toString()); }, [EIssueActions.DELETE]: async (issue: IIssue) => { if (!workspaceSlug || !cycleId) return; - cycleIssueStore.removeIssue(workspaceSlug, issue.project, issue.id, cycleId); + await cycleIssueStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id, cycleId.toString()); }, [EIssueActions.REMOVE]: async (issue: IIssue) => { - if (!workspaceSlug || !cycleId || !issue.bridge_id) return; - cycleIssueStore.removeIssueFromCycle(workspaceSlug, issue.project, cycleId, issue.id, issue.bridge_id); + if (!workspaceSlug || !cycleId || !projectId || !issue.bridge_id) return; + await cycleIssueStore.removeIssueFromCycle( + workspaceSlug.toString(), + issue.project, + cycleId.toString(), + issue.id, + issue.bridge_id + ); }, }; const handleDragDrop = (source: any, destination: any, issues: IIssue[], issueWithIds: any) => { - if (calendarHelperStore.handleDragDrop) - calendarHelperStore.handleDragDrop( + if (workspaceSlug && projectId && cycleId) + handleCalenderDragDrop( source, destination, - workspaceSlug, - projectId, + workspaceSlug.toString(), + projectId.toString(), cycleIssueStore, issues, issueWithIds, - cycleId + cycleId.toString() ); }; + if (!cycleId) return null; + return ( { calendarViewStore={cycleIssueCalendarViewStore} QuickActions={CycleIssueQuickActions} issueActions={issueActions} - viewId={cycleId} + viewId={cycleId.toString()} handleDragDrop={handleDragDrop} /> ); diff --git a/web/components/issues/issue-layouts/calendar/roots/module-root.tsx b/web/components/issues/issue-layouts/calendar/roots/module-root.tsx index e8d66e04b..f4d33a7ec 100644 --- a/web/components/issues/issue-layouts/calendar/roots/module-root.tsx +++ b/web/components/issues/issue-layouts/calendar/roots/module-root.tsx @@ -14,7 +14,7 @@ export const ModuleCalendarLayout: React.FC = observer(() => { moduleIssues: moduleIssueStore, moduleIssuesFilter: moduleIssueFilterStore, moduleIssueCalendarView: moduleIssueCalendarViewStore, - calendarHelpers: calendarHelperStore, + calendarHelpers: { handleDragDrop: handleCalenderDragDrop }, } = useMobxStore(); const router = useRouter(); @@ -25,32 +25,31 @@ export const ModuleCalendarLayout: React.FC = observer(() => { }; const issueActions = { - [EIssueActions.UPDATE]: (issue: IIssue) => { + [EIssueActions.UPDATE]: async (issue: IIssue) => { if (!workspaceSlug || !moduleId) return; - moduleIssueStore.updateIssue(workspaceSlug, issue.project, issue.id, issue, moduleId); + await moduleIssueStore.updateIssue(workspaceSlug, issue.project, issue.id, issue, moduleId); }, - [EIssueActions.DELETE]: (issue: IIssue) => { + [EIssueActions.DELETE]: async (issue: IIssue) => { if (!workspaceSlug || !moduleId) return; - moduleIssueStore.removeIssue(workspaceSlug, issue.project, issue.id, moduleId); + await moduleIssueStore.removeIssue(workspaceSlug, issue.project, issue.id, moduleId); }, - [EIssueActions.REMOVE]: (issue: IIssue) => { + [EIssueActions.REMOVE]: async (issue: IIssue) => { if (!workspaceSlug || !moduleId || !issue.bridge_id) return; - moduleIssueStore.removeIssueFromModule(workspaceSlug, issue.project, moduleId, issue.id, issue.bridge_id); + await moduleIssueStore.removeIssueFromModule(workspaceSlug, issue.project, moduleId, issue.id, issue.bridge_id); }, }; const handleDragDrop = (source: any, destination: any, issues: IIssue[], issueWithIds: any) => { - if (calendarHelperStore.handleDragDrop) - calendarHelperStore.handleDragDrop( - source, - destination, - workspaceSlug, - projectId, - moduleIssueStore, - issues, - issueWithIds, - moduleId - ); + handleCalenderDragDrop( + source, + destination, + workspaceSlug, + projectId, + moduleIssueStore, + issues, + issueWithIds, + moduleId + ); }; return ( diff --git a/web/components/issues/issue-layouts/calendar/roots/project-root.tsx b/web/components/issues/issue-layouts/calendar/roots/project-root.tsx index 254dd714c..1be4ed096 100644 --- a/web/components/issues/issue-layouts/calendar/roots/project-root.tsx +++ b/web/components/issues/issue-layouts/calendar/roots/project-root.tsx @@ -10,35 +10,35 @@ import { useRouter } from "next/router"; export const CalendarLayout: React.FC = observer(() => { const router = useRouter(); - const { workspaceSlug, projectId } = router.query as { workspaceSlug: string; projectId: string }; + const { workspaceSlug, projectId } = router.query; const { projectIssues: issueStore, issueCalendarView: issueCalendarViewStore, projectIssuesFilter: projectIssueFiltersStore, - calendarHelpers: calendarHelperStore, + calendarHelpers: { handleDragDrop: handleCalenderDragDrop }, } = useMobxStore(); const issueActions = { [EIssueActions.UPDATE]: async (issue: IIssue) => { if (!workspaceSlug) return; - issueStore.updateIssue(workspaceSlug, issue.project, issue.id, issue); + await issueStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue); }, [EIssueActions.DELETE]: async (issue: IIssue) => { if (!workspaceSlug) return; - issueStore.removeIssue(workspaceSlug, issue.project, issue.id); + await issueStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id); }, }; const handleDragDrop = (source: any, destination: any, issues: IIssue[], issueWithIds: any) => { - if (calendarHelperStore.handleDragDrop) - calendarHelperStore.handleDragDrop( + if (workspaceSlug && projectId) + handleCalenderDragDrop( source, destination, - workspaceSlug, - projectId, + workspaceSlug.toString(), + projectId.toString(), issueStore, issues, issueWithIds diff --git a/web/components/issues/issue-layouts/calendar/roots/project-view-root.tsx b/web/components/issues/issue-layouts/calendar/roots/project-view-root.tsx index 0cf116749..cab3203c7 100644 --- a/web/components/issues/issue-layouts/calendar/roots/project-view-root.tsx +++ b/web/components/issues/issue-layouts/calendar/roots/project-view-root.tsx @@ -14,32 +14,32 @@ export const ProjectViewCalendarLayout: React.FC = observer(() => { viewIssues: projectViewIssuesStore, viewIssuesFilter: projectIssueViewFiltersStore, projectViewIssueCalendarView: projectViewIssueCalendarViewStore, - calendarHelpers: calendarHelperStore, + calendarHelpers: { handleDragDrop: handleCalenderDragDrop }, } = useMobxStore(); const router = useRouter(); - const { workspaceSlug, projectId } = router.query as { workspaceSlug: string; projectId: string }; + const { workspaceSlug, projectId } = router.query; const issueActions = { [EIssueActions.UPDATE]: async (issue: IIssue) => { if (!workspaceSlug) return; - projectViewIssuesStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue); + await projectViewIssuesStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue); }, [EIssueActions.DELETE]: async (issue: IIssue) => { if (!workspaceSlug) return; - projectViewIssuesStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id); + await projectViewIssuesStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id); }, }; const handleDragDrop = (source: any, destination: any, issues: IIssue[], issueWithIds: any) => { - if (calendarHelperStore.handleDragDrop) - calendarHelperStore.handleDragDrop( + if (workspaceSlug && projectId) + handleCalenderDragDrop( source, destination, - workspaceSlug, - projectId, + workspaceSlug.toString(), + projectId.toString(), projectViewIssuesStore, issues, issueWithIds diff --git a/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx b/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx index 5e4a53b87..695ca21a3 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx +++ b/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx @@ -1,6 +1,5 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; - // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components @@ -26,7 +25,6 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => { projectState: projectStateStore, projectMember: { projectMembers }, projectViews: projectViewsStore, - projectViewFilters: projectViewFiltersStore, viewIssuesFilter: { issueFilters, updateFilters }, } = useMobxStore(); diff --git a/web/components/issues/issue-layouts/gantt/base-gantt-root.tsx b/web/components/issues/issue-layouts/gantt/base-gantt-root.tsx index bf7ed2b42..0c9a9988f 100644 --- a/web/components/issues/issue-layouts/gantt/base-gantt-root.tsx +++ b/web/components/issues/issue-layouts/gantt/base-gantt-root.tsx @@ -54,11 +54,11 @@ export const BaseGanttRoot: React.FC = observer((props: IBaseGan const issues = issueIds.map((id) => issuesResponse?.[id]); - const updateIssue = (issue: IIssue, payload: IBlockUpdateData) => { + const updateIssue = async (issue: IIssue, payload: IBlockUpdateData) => { if (!workspaceSlug) return; //Todo fix sort order in the structure - issueStore.updateIssue( + await issueStore.updateIssue( workspaceSlug.toString(), issue.project, issue.id, @@ -101,9 +101,9 @@ export const BaseGanttRoot: React.FC = observer((props: IBaseGan workspaceSlug={workspaceSlug.toString()} projectId={peekProjectId.toString()} issueId={peekIssueId.toString()} - handleIssue={(issueToUpdate) => { + handleIssue={async (issueToUpdate) => { // TODO: update the logic here - updateIssue(issueToUpdate as IIssue, {}); + await updateIssue(issueToUpdate as IIssue, {}); }} /> )} diff --git a/web/components/issues/issue-layouts/kanban/base-kanban-root.tsx b/web/components/issues/issue-layouts/kanban/base-kanban-root.tsx index 45e369f67..b3a091cb3 100644 --- a/web/components/issues/issue-layouts/kanban/base-kanban-root.tsx +++ b/web/components/issues/issue-layouts/kanban/base-kanban-root.tsx @@ -52,9 +52,9 @@ export interface IBaseKanBanLayout { kanbanViewStore: IIssueKanBanViewStore; QuickActions: FC; issueActions: { - [EIssueActions.DELETE]: (issue: IIssue) => void; - [EIssueActions.UPDATE]?: (issue: IIssue) => void; - [EIssueActions.REMOVE]?: (issue: IIssue) => void; + [EIssueActions.DELETE]: (issue: IIssue) => Promise; + [EIssueActions.UPDATE]?: (issue: IIssue) => Promise; + [EIssueActions.REMOVE]?: (issue: IIssue) => Promise; }; showLoader?: boolean; viewId?: string; @@ -169,7 +169,7 @@ export const BaseKanBanRoot: React.FC = observer((props: IBas const handleIssues = useCallback( async (sub_group_by: string | null, group_by: string | null, issue: IIssue, action: EIssueActions) => { if (issueActions[action]) { - issueActions[action]!(issue); + await issueActions[action]!(issue); } }, [issueActions] @@ -345,8 +345,8 @@ export const BaseKanBanRoot: React.FC = observer((props: IBas workspaceSlug={workspaceSlug.toString()} projectId={peekProjectId.toString()} issueId={peekIssueId.toString()} - handleIssue={(issueToUpdate) => - handleIssues(sub_group_by, group_by, issueToUpdate as IIssue, EIssueActions.UPDATE) + handleIssue={async (issueToUpdate) => + await handleIssues(sub_group_by, group_by, issueToUpdate as IIssue, EIssueActions.UPDATE) } /> )} diff --git a/web/components/issues/issue-layouts/kanban/roots/cycle-root.tsx b/web/components/issues/issue-layouts/kanban/roots/cycle-root.tsx index 6f47b57d1..3c3ee69bc 100644 --- a/web/components/issues/issue-layouts/kanban/roots/cycle-root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/cycle-root.tsx @@ -17,11 +17,7 @@ export interface ICycleKanBanLayout {} export const CycleKanBanLayout: React.FC = observer(() => { const router = useRouter(); - const { workspaceSlug, projectId, cycleId } = router.query as { - workspaceSlug: string; - projectId: string; - cycleId: string; - }; + const { workspaceSlug, projectId, cycleId } = router.query; // store const { @@ -35,15 +31,23 @@ export const CycleKanBanLayout: React.FC = observer(() => { [EIssueActions.UPDATE]: async (issue: IIssue) => { if (!workspaceSlug || !cycleId) return; - cycleIssueStore.updateIssue(workspaceSlug, issue.project, issue.id, issue, cycleId); + await cycleIssueStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue, cycleId.toString()); }, [EIssueActions.DELETE]: async (issue: IIssue) => { if (!workspaceSlug || !cycleId) return; - cycleIssueStore.removeIssue(workspaceSlug, issue.project, issue.id, cycleId); + + await cycleIssueStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id, cycleId.toString()); }, [EIssueActions.REMOVE]: async (issue: IIssue) => { if (!workspaceSlug || !cycleId || !issue.bridge_id) return; - cycleIssueStore.removeIssueFromCycle(workspaceSlug, issue.project, cycleId, issue.id, issue.bridge_id); + + await cycleIssueStore.removeIssueFromCycle( + workspaceSlug.toString(), + issue.project, + cycleId.toString(), + issue.id, + issue.bridge_id + ); }, }; @@ -55,18 +59,18 @@ export const CycleKanBanLayout: React.FC = observer(() => { issues: IIssueResponse | undefined, issueWithIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined ) => { - if (kanBanHelperStore.handleDragDrop) + if (workspaceSlug && projectId && cycleId) return await kanBanHelperStore.handleDragDrop( source, destination, - workspaceSlug, - projectId, + workspaceSlug.toString(), + projectId.toString(), cycleIssueStore, subGroupBy, groupBy, issues, issueWithIds, - cycleId + cycleId.toString() ); }; @@ -78,10 +82,12 @@ export const CycleKanBanLayout: React.FC = observer(() => { kanbanViewStore={cycleIssueKanBanViewStore} showLoader={true} QuickActions={CycleIssueQuickActions} - viewId={cycleId} + viewId={cycleId?.toString() ?? ""} currentStore={EProjectStore.CYCLE} handleDragDrop={handleDragDrop} - addIssuesToView={(issues: string[]) => cycleIssueStore.addIssueToCycle(workspaceSlug, cycleId, issues)} + addIssuesToView={(issues: string[]) => + cycleIssueStore.addIssueToCycle(workspaceSlug?.toString() ?? "", cycleId?.toString() ?? "", issues) + } /> ); }); diff --git a/web/components/issues/issue-layouts/kanban/roots/draft-issue-root.tsx b/web/components/issues/issue-layouts/kanban/roots/draft-issue-root.tsx index 434de6259..78f5a76eb 100644 --- a/web/components/issues/issue-layouts/kanban/roots/draft-issue-root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/draft-issue-root.tsx @@ -14,7 +14,7 @@ export interface IKanBanLayout {} export const DraftKanBanLayout: React.FC = observer(() => { const router = useRouter(); - const { workspaceSlug } = router.query as { workspaceSlug: string }; + const { workspaceSlug } = router.query; const { projectDraftIssues: issueStore, @@ -26,12 +26,12 @@ export const DraftKanBanLayout: React.FC = observer(() => { [EIssueActions.UPDATE]: async (issue: IIssue) => { if (!workspaceSlug) return; - await issueStore.updateIssue(workspaceSlug, issue.project, issue.id, issue); + await issueStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue); }, [EIssueActions.DELETE]: async (issue: IIssue) => { if (!workspaceSlug) return; - await issueStore.removeIssue(workspaceSlug, issue.project, issue.id); + await issueStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id); }, }; diff --git a/web/components/issues/issue-layouts/kanban/roots/module-root.tsx b/web/components/issues/issue-layouts/kanban/roots/module-root.tsx index a683a710e..168460026 100644 --- a/web/components/issues/issue-layouts/kanban/roots/module-root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/module-root.tsx @@ -17,11 +17,7 @@ export interface IModuleKanBanLayout {} export const ModuleKanBanLayout: React.FC = observer(() => { const router = useRouter(); - const { workspaceSlug, projectId, moduleId } = router.query as { - workspaceSlug: string; - projectId: string; - moduleId: string; - }; + const { workspaceSlug, projectId, moduleId } = router.query; // store const { @@ -35,15 +31,23 @@ export const ModuleKanBanLayout: React.FC = observer(() => { [EIssueActions.UPDATE]: async (issue: IIssue) => { if (!workspaceSlug || !moduleId) return; - moduleIssueStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue, moduleId); + await moduleIssueStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue, moduleId.toString()); }, [EIssueActions.DELETE]: async (issue: IIssue) => { if (!workspaceSlug || !moduleId) return; - moduleIssueStore.removeIssue(workspaceSlug, issue.project, issue.id, moduleId); + + await moduleIssueStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id, moduleId.toString()); }, [EIssueActions.REMOVE]: async (issue: IIssue) => { if (!workspaceSlug || !moduleId || !issue.bridge_id) return; - moduleIssueStore.removeIssueFromModule(workspaceSlug, issue.project, moduleId, issue.id, issue.bridge_id); + + await moduleIssueStore.removeIssueFromModule( + workspaceSlug.toString(), + issue.project, + moduleId.toString(), + issue.id, + issue.bridge_id + ); }, }; @@ -55,18 +59,18 @@ export const ModuleKanBanLayout: React.FC = observer(() => { issues: IIssueResponse | undefined, issueWithIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined ) => { - if (kanBanHelperStore.handleDragDrop) + if (workspaceSlug && projectId && moduleId) return await kanBanHelperStore.handleDragDrop( source, destination, - workspaceSlug, - projectId, + workspaceSlug.toString(), + projectId.toString(), moduleIssueStore, subGroupBy, groupBy, issues, issueWithIds, - moduleId + moduleId.toString() ); }; return ( @@ -77,10 +81,12 @@ export const ModuleKanBanLayout: React.FC = observer(() => { kanbanViewStore={moduleIssueKanBanViewStore} showLoader={true} QuickActions={ModuleIssueQuickActions} - viewId={moduleId} + viewId={moduleId?.toString() ?? ""} currentStore={EProjectStore.MODULE} handleDragDrop={handleDragDrop} - addIssuesToView={(issues: string[]) => moduleIssueStore.addIssueToModule(workspaceSlug, moduleId, issues)} + addIssuesToView={(issues: string[]) => + moduleIssueStore.addIssueToModule(workspaceSlug?.toString() ?? "", moduleId?.toString() ?? "", issues) + } /> ); }); diff --git a/web/components/issues/issue-layouts/kanban/roots/project-root.tsx b/web/components/issues/issue-layouts/kanban/roots/project-root.tsx index 5566ca028..16ef0f65b 100644 --- a/web/components/issues/issue-layouts/kanban/roots/project-root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/project-root.tsx @@ -45,20 +45,18 @@ export const KanBanLayout: React.FC = observer(() => { groupBy: string | null, issues: IIssueResponse | undefined, issueWithIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined - ) => { - if (kanBanHelperStore.handleDragDrop) - return await kanBanHelperStore.handleDragDrop( - source, - destination, - workspaceSlug, - projectId, - issueStore, - subGroupBy, - groupBy, - issues, - issueWithIds - ); - }; + ) => + await kanBanHelperStore.handleDragDrop( + source, + destination, + workspaceSlug, + projectId, + issueStore, + subGroupBy, + groupBy, + issues, + issueWithIds + ); return ( { groupBy: string | null, issues: IIssueResponse | undefined, issueWithIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined - ) => { - if (kanBanHelperStore.handleDragDrop) - return await kanBanHelperStore.handleDragDrop( - source, - destination, - workspaceSlug, - projectId, - projectViewIssuesStore, - subGroupBy, - groupBy, - issues, - issueWithIds - ); - }; + ) => + await kanBanHelperStore.handleDragDrop( + source, + destination, + workspaceSlug, + projectId, + projectViewIssuesStore, + subGroupBy, + groupBy, + issues, + issueWithIds + ); return ( ; issueActions: { - [EIssueActions.DELETE]: (group_by: string | null, issue: IIssue) => void; - [EIssueActions.UPDATE]?: (group_by: string | null, issue: IIssue) => void; - [EIssueActions.REMOVE]?: (group_by: string | null, issue: IIssue) => void; + [EIssueActions.DELETE]: (group_by: string | null, issue: IIssue) => Promise; + [EIssueActions.UPDATE]?: (group_by: string | null, issue: IIssue) => Promise; + [EIssueActions.REMOVE]?: (group_by: string | null, issue: IIssue) => Promise; }; getProjects: (projectStore: IProjectStore) => IProject[] | null; viewId?: string; @@ -105,7 +105,7 @@ export const BaseListRoot = observer((props: IBaseListRoot) => { const members = projectMembers?.map((m) => m.member) ?? null; const handleIssues = async (issue: IIssue, action: EIssueActions) => { if (issueActions[action]) { - issueActions[action]!(group_by, issue); + await issueActions[action]!(group_by, issue); } }; @@ -160,7 +160,7 @@ export const BaseListRoot = observer((props: IBaseListRoot) => { workspaceSlug={workspaceSlug.toString()} projectId={peekProjectId.toString()} issueId={peekIssueId.toString()} - handleIssue={(issueToUpdate) => handleIssues(issueToUpdate as IIssue, EIssueActions.UPDATE)} + handleIssue={async (issueToUpdate) => await handleIssues(issueToUpdate as IIssue, EIssueActions.UPDATE)} /> )} diff --git a/web/components/issues/issue-layouts/list/roots/archived-issue-root.tsx b/web/components/issues/issue-layouts/list/roots/archived-issue-root.tsx index 6cd66a0e8..cf4c74063 100644 --- a/web/components/issues/issue-layouts/list/roots/archived-issue-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/archived-issue-root.tsx @@ -21,10 +21,10 @@ export const ArchivedIssueListLayout: FC = observer(() => { useMobxStore(); const issueActions = { - [EIssueActions.DELETE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.DELETE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !projectId) return; - archivedIssueStore.removeIssue(workspaceSlug, projectId, issue.id); + await archivedIssueStore.removeIssue(workspaceSlug, projectId, issue.id); }, }; diff --git a/web/components/issues/issue-layouts/list/roots/cycle-root.tsx b/web/components/issues/issue-layouts/list/roots/cycle-root.tsx index b9a532eb5..1ce28d008 100644 --- a/web/components/issues/issue-layouts/list/roots/cycle-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/cycle-root.tsx @@ -22,17 +22,20 @@ export const CycleListLayout: React.FC = observer(() => { const { cycleIssues: cycleIssueStore, cycleIssuesFilter: cycleIssueFilterStore } = useMobxStore(); const issueActions = { - [EIssueActions.UPDATE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.UPDATE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !cycleId) return; - cycleIssueStore.updateIssue(workspaceSlug, issue.project, issue.id, issue, cycleId); + + await cycleIssueStore.updateIssue(workspaceSlug, issue.project, issue.id, issue, cycleId); }, - [EIssueActions.DELETE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.DELETE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !cycleId) return; - cycleIssueStore.removeIssue(workspaceSlug, issue.project, issue.id, cycleId); + + await cycleIssueStore.removeIssue(workspaceSlug, issue.project, issue.id, cycleId); }, - [EIssueActions.REMOVE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.REMOVE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !cycleId || !issue.bridge_id) return; - cycleIssueStore.removeIssueFromCycle(workspaceSlug, issue.project, cycleId, issue.id, issue.bridge_id); + + await cycleIssueStore.removeIssueFromCycle(workspaceSlug, issue.project, cycleId, issue.id, issue.bridge_id); }, }; const getProjects = (projectStore: IProjectStore) => { diff --git a/web/components/issues/issue-layouts/list/roots/draft-issue-root.tsx b/web/components/issues/issue-layouts/list/roots/draft-issue-root.tsx index 24b4cf324..6049ec3bc 100644 --- a/web/components/issues/issue-layouts/list/roots/draft-issue-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/draft-issue-root.tsx @@ -23,13 +23,15 @@ export const DraftIssueListLayout: FC = observer(() => { const { projectDraftIssuesFilter: projectIssuesFilterStore, projectDraftIssues: projectIssuesStore } = useMobxStore(); const issueActions = { - [EIssueActions.UPDATE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.UPDATE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !projectId) return; - projectIssuesStore.updateIssue(workspaceSlug, projectId, issue.id, issue); + + await projectIssuesStore.updateIssue(workspaceSlug, projectId, issue.id, issue); }, - [EIssueActions.DELETE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.DELETE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !projectId) return; - projectIssuesStore.removeIssue(workspaceSlug, projectId, issue.id); + + await projectIssuesStore.removeIssue(workspaceSlug, projectId, issue.id); }, }; diff --git a/web/components/issues/issue-layouts/list/roots/module-root.tsx b/web/components/issues/issue-layouts/list/roots/module-root.tsx index c5c7eda5e..2c8737e70 100644 --- a/web/components/issues/issue-layouts/list/roots/module-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/module-root.tsx @@ -22,17 +22,20 @@ export const ModuleListLayout: React.FC = observer(() => { const { moduleIssues: moduleIssueStore, moduleIssuesFilter: moduleIssueFilterStore } = useMobxStore(); const issueActions = { - [EIssueActions.UPDATE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.UPDATE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !moduleId) return; - moduleIssueStore.updateIssue(workspaceSlug, issue.project, issue.id, issue, moduleId); + + await moduleIssueStore.updateIssue(workspaceSlug, issue.project, issue.id, issue, moduleId); }, - [EIssueActions.DELETE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.DELETE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !moduleId) return; - moduleIssueStore.removeIssue(workspaceSlug, issue.project, issue.id, moduleId); + + await moduleIssueStore.removeIssue(workspaceSlug, issue.project, issue.id, moduleId); }, - [EIssueActions.REMOVE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.REMOVE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !moduleId || !issue.bridge_id) return; - moduleIssueStore.removeIssueFromModule(workspaceSlug, issue.project, moduleId, issue.id, issue.bridge_id); + + await moduleIssueStore.removeIssueFromModule(workspaceSlug, issue.project, moduleId, issue.id, issue.bridge_id); }, }; diff --git a/web/components/issues/issue-layouts/list/roots/project-root.tsx b/web/components/issues/issue-layouts/list/roots/project-root.tsx index a7023c62d..0d23f7656 100644 --- a/web/components/issues/issue-layouts/list/roots/project-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/project-root.tsx @@ -23,13 +23,15 @@ export const ListLayout: FC = observer(() => { const { projectIssuesFilter: projectIssuesFilterStore, projectIssues: projectIssuesStore } = useMobxStore(); const issueActions = { - [EIssueActions.UPDATE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.UPDATE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !projectId) return; - projectIssuesStore.updateIssue(workspaceSlug, projectId, issue.id, issue); + + await projectIssuesStore.updateIssue(workspaceSlug, projectId, issue.id, issue); }, - [EIssueActions.DELETE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.DELETE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !projectId) return; - projectIssuesStore.removeIssue(workspaceSlug, projectId, issue.id); + + await projectIssuesStore.removeIssue(workspaceSlug, projectId, issue.id); }, }; diff --git a/web/components/issues/issue-layouts/list/roots/project-view-root.tsx b/web/components/issues/issue-layouts/list/roots/project-view-root.tsx index 713f839aa..52fa1a759 100644 --- a/web/components/issues/issue-layouts/list/roots/project-view-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/project-view-root.tsx @@ -26,13 +26,15 @@ export const ProjectViewListLayout: React.FC = observer(() => { if (!workspaceSlug || !projectId) return null; const issueActions = { - [EIssueActions.UPDATE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.UPDATE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !projectId) return; - projectViewIssueStore.updateIssue(workspaceSlug, projectId, issue.id, issue); + + await projectViewIssueStore.updateIssue(workspaceSlug, projectId, issue.id, issue); }, - [EIssueActions.DELETE]: (group_by: string | null, issue: IIssue) => { + [EIssueActions.DELETE]: async (group_by: string | null, issue: IIssue) => { if (!workspaceSlug || !projectId) return; - projectViewIssueStore.removeIssue(workspaceSlug, projectId, issue.id); + + await projectViewIssueStore.removeIssue(workspaceSlug, projectId, issue.id); }, }; diff --git a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx index 5a29ed91b..8eb98d512 100644 --- a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx @@ -21,8 +21,8 @@ type Props = { members?: IUserLite[] | undefined; labels?: IIssueLabel[] | undefined; states?: IState[] | undefined; - quickActions: (issue: IIssue,customActionButton?: React.ReactElement) => React.ReactNode; - handleIssues: (issue: IIssue, action: EIssueActions) => void; + quickActions: (issue: IIssue, customActionButton: any) => React.ReactNode; // TODO: replace any with type + handleIssues: (issue: IIssue, action: EIssueActions) => Promise; openIssuesListModal?: (() => void) | null; quickAddCallback?: ( workspaceSlug: string, @@ -189,7 +189,7 @@ export const SpreadsheetView: React.FC = observer((props) => { workspaceSlug={workspaceSlug.toString()} projectId={peekProjectId.toString()} issueId={peekIssueId.toString()} - handleIssue={(issueToUpdate: any) => handleIssues(issueToUpdate, EIssueActions.UPDATE)} + handleIssue={async (issueToUpdate: any) => await handleIssues(issueToUpdate, EIssueActions.UPDATE)} /> )}
diff --git a/web/components/issues/issue-peek-overview/index.ts b/web/components/issues/issue-peek-overview/index.ts deleted file mode 100644 index 1efe34c51..000000000 --- a/web/components/issues/issue-peek-overview/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./root"; diff --git a/web/components/issues/issue-reaction.tsx b/web/components/issues/issue-reaction.tsx index 2c0f0b3ff..54b75e6a0 100644 --- a/web/components/issues/issue-reaction.tsx +++ b/web/components/issues/issue-reaction.tsx @@ -1,22 +1,25 @@ // hooks -import useUserAuth from "hooks/use-user-auth"; import useIssueReaction from "hooks/use-issue-reaction"; // components import { ReactionSelector } from "components/core"; // string helpers import { renderEmoji } from "helpers/emoji.helper"; +import { observer } from "mobx-react-lite"; +import { useMobxStore } from "lib/mobx/store-provider"; // types type Props = { - workspaceSlug?: string | string[]; - projectId?: string | string[]; - issueId?: string | string[]; + workspaceSlug: string; + projectId: string; + issueId: string; }; -export const IssueReaction: React.FC = (props) => { +export const IssueReaction: React.FC = observer((props) => { const { workspaceSlug, projectId, issueId } = props; - const { user } = useUserAuth(); + const { + user: { currentUser }, + } = useMobxStore(); const { reactions, groupedReactions, handleReactionCreate, handleReactionDelete } = useIssueReaction( workspaceSlug, @@ -27,7 +30,7 @@ export const IssueReaction: React.FC = (props) => { const handleReactionClick = (reaction: string) => { if (!workspaceSlug || !projectId || !issueId) return; - const isSelected = reactions?.some((r) => r.actor === user?.id && r.reaction === reaction); + const isSelected = reactions?.some((r) => r.actor === currentUser?.id && r.reaction === reaction); if (isSelected) { handleReactionDelete(reaction); @@ -41,7 +44,7 @@ export const IssueReaction: React.FC = (props) => { reaction.actor === user?.id).map((r) => r.reaction) || []} + value={reactions?.filter((reaction) => reaction.actor === currentUser?.id).map((r) => r.reaction) || []} onSelect={handleReactionClick} /> @@ -56,7 +59,7 @@ export const IssueReaction: React.FC = (props) => { }} key={reaction} className={`flex items-center gap-1 text-custom-text-100 text-sm h-full px-2 py-1 rounded-md ${ - reactions?.some((r) => r.actor === user?.id && r.reaction === reaction) + reactions?.some((r) => r.actor === currentUser?.id && r.reaction === reaction) ? "bg-custom-primary-100/10" : "bg-custom-background-80" }`} @@ -64,7 +67,7 @@ export const IssueReaction: React.FC = (props) => { {renderEmoji(reaction)} r.actor === user?.id && r.reaction === reaction) + reactions?.some((r) => r.actor === currentUser?.id && r.reaction === reaction) ? "text-custom-primary-100" : "" } @@ -76,4 +79,4 @@ export const IssueReaction: React.FC = (props) => { )} ); -}; +}); diff --git a/web/components/issues/main-content.tsx b/web/components/issues/main-content.tsx index f03d0a7cc..2eca81609 100644 --- a/web/components/issues/main-content.tsx +++ b/web/components/issues/main-content.tsx @@ -24,9 +24,10 @@ import { SubIssuesRoot } from "./sub-issues"; // ui import { CustomMenu, LayersIcon, StateGroupIcon } from "@plane/ui"; // types -import { IIssue, IIssueComment } from "types"; +import { IIssue, IIssueActivity } from "types"; // fetch-keys import { PROJECT_ISSUES_ACTIVITY, SUB_ISSUES } from "constants/fetch-keys"; +// constants import { EUserWorkspaceRoles } from "constants/workspace"; type Props = { @@ -41,24 +42,22 @@ const issueCommentService = new IssueCommentService(); export const IssueMainContent: React.FC = observer((props) => { const { issueDetails, submitChanges, uneditable = false } = props; - // states const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved"); - + // router const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; - + // toast alert const { setToastAlert } = useToast(); - + // mobx store const { - user: userStore, + user: { currentUser, currentProjectRole }, project: projectStore, projectState: { states }, trackEvent: { postHogEventTracker }, workspace: { currentWorkspace } } = useMobxStore(); - const user = userStore.currentUser ?? undefined; - const userRole = userStore.currentProjectRole; + const projectDetails = projectId ? projectStore.project_details[projectId.toString()] : undefined; const currentIssueState = projectId ? states[projectId.toString()]?.find((s) => s.id === issueDetails.state) @@ -67,7 +66,7 @@ export const IssueMainContent: React.FC = observer((props) => { const { data: siblingIssues } = useSWR( workspaceSlug && projectId && issueDetails?.parent ? SUB_ISSUES(issueDetails.parent) : null, workspaceSlug && projectId && issueDetails?.parent - ? () => issueService.subIssues(workspaceSlug as string, projectId as string, issueDetails.parent ?? "") + ? () => issueService.subIssues(workspaceSlug.toString(), projectId.toString(), issueDetails.parent ?? "") : null ); const siblingIssuesList = siblingIssues?.sub_issues.filter((i) => i.id !== issueDetails.id); @@ -79,7 +78,7 @@ export const IssueMainContent: React.FC = observer((props) => { : null ); - const handleCommentUpdate = async (commentId: string, data: Partial) => { + const handleCommentUpdate = async (commentId: string, data: Partial) => { if (!workspaceSlug || !projectId || !issueId) return; await issueCommentService @@ -103,7 +102,7 @@ export const IssueMainContent: React.FC = observer((props) => { }; const handleCommentDelete = async (commentId: string) => { - if (!workspaceSlug || !projectId || !issueId || !user) return; + if (!workspaceSlug || !projectId || !issueId || !currentUser) return; mutateIssueActivity((prevData: any) => prevData?.filter((p: any) => p.id !== commentId), false); @@ -126,8 +125,8 @@ export const IssueMainContent: React.FC = observer((props) => { ); }; - const handleAddComment = async (formData: IIssueComment) => { - if (!workspaceSlug || !issueDetails || !user) return; + const handleAddComment = async (formData: IIssueActivity) => { + if (!workspaceSlug || !issueDetails || !currentUser) return; await issueCommentService .createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData) @@ -155,7 +154,7 @@ export const IssueMainContent: React.FC = observer((props) => { ); }; - const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER; + const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; return ( <> @@ -238,10 +237,16 @@ export const IssueMainContent: React.FC = observer((props) => { isAllowed={isAllowed || !uneditable} /> - + {workspaceSlug && projectId && ( + + )}
- +
diff --git a/web/components/issues/issue-peek-overview/activity/card.tsx b/web/components/issues/peek-overview/activity/card.tsx similarity index 87% rename from web/components/issues/issue-peek-overview/activity/card.tsx rename to web/components/issues/peek-overview/activity/card.tsx index c677a6402..198bef675 100644 --- a/web/components/issues/issue-peek-overview/activity/card.tsx +++ b/web/components/issues/peek-overview/activity/card.tsx @@ -2,32 +2,34 @@ import { FC } from "react"; import Link from "next/link"; import { History } from "lucide-react"; // packages -import { Tooltip } from "@plane/ui"; +import { Loader, Tooltip } from "@plane/ui"; // components import { ActivityIcon, ActivityMessage } from "components/core"; import { IssueCommentCard } from "./comment-card"; // helpers import { render24HourFormatTime, renderLongDateFormat, timeAgo } from "helpers/date-time.helper"; +// types +import { IIssueActivity, IUser } from "types"; -interface IssueActivityCard { +interface IIssueActivityCard { workspaceSlug: string; projectId: string; issueId: string; - user: any; - issueComments: any; + user: IUser | null; + issueActivity: IIssueActivity[] | null; issueCommentUpdate: (comment: any) => void; issueCommentRemove: (commentId: string) => void; issueCommentReactionCreate: (commentId: string, reaction: string) => void; issueCommentReactionRemove: (commentId: string, reaction: string) => void; } -export const IssueActivityCard: FC = (props) => { +export const IssueActivityCard: FC = (props) => { const { workspaceSlug, projectId, issueId, user, - issueComments, + issueActivity, issueCommentUpdate, issueCommentRemove, issueCommentReactionCreate, @@ -37,9 +39,9 @@ export const IssueActivityCard: FC = (props) => { return (
    - {issueComments && - issueComments.length > 0 && - issueComments.map((activityItem: any, index: any) => { + {issueActivity ? ( + issueActivity.length > 0 && + issueActivity.map((activityItem, index) => { // determines what type of action is performed const message = activityItem.field ? : "created the issue."; @@ -47,7 +49,7 @@ export const IssueActivityCard: FC = (props) => { return (
  • - {issueComments.length > 1 && index !== issueComments.length - 1 ? ( + {issueActivity.length > 1 && index !== issueActivity.length - 1 ? (
  • ); - } else if ("comment_json" in activityItem) + } else if ("comment_html" in activityItem) return (
    = (props) => { />
    ); - })} + }) + ) : ( + + + + + + + )}
); diff --git a/web/components/issues/issue-peek-overview/activity/comment-card.tsx b/web/components/issues/peek-overview/activity/comment-card.tsx similarity index 94% rename from web/components/issues/issue-peek-overview/activity/comment-card.tsx rename to web/components/issues/peek-overview/activity/comment-card.tsx index f576e767e..d530419a1 100644 --- a/web/components/issues/issue-peek-overview/activity/comment-card.tsx +++ b/web/components/issues/peek-overview/activity/comment-card.tsx @@ -12,20 +12,20 @@ import { IssueCommentReaction } from "./comment-reaction"; // helpers import { timeAgo } from "helpers/date-time.helper"; // types -import type { IIssueComment } from "types"; +import type { IIssueActivity, IUser } from "types"; // services const fileService = new FileService(); type IIssueCommentCard = { - comment: IIssueComment; + comment: IIssueActivity; handleCommentDeletion: (comment: string) => void; - onSubmit: (data: Partial) => void; + onSubmit: (data: Partial) => void; showAccessSpecifier?: boolean; workspaceSlug: string; projectId: string; issueId: string; - user: any; + user: IUser | null; issueCommentReactionCreate: (commentId: string, reaction: string) => void; issueCommentReactionRemove: (commentId: string, reaction: string) => void; }; @@ -57,11 +57,11 @@ export const IssueCommentCard: React.FC = (props) => { setFocus, watch, setValue, - } = useForm({ + } = useForm({ defaultValues: comment, }); - const formSubmit = (formData: Partial) => { + const formSubmit = (formData: Partial) => { if (isSubmitting) return; setIsEditing(false); @@ -119,13 +119,10 @@ export const IssueCommentCard: React.FC = (props) => { deleteFile={fileService.deleteImage} restoreFile={fileService.restoreImage} ref={editorRef} - value={watch("comment_html")} + 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); - }} + onChange={(comment_json: Object, comment_html: string) => setValue("comment_html", comment_html)} mentionSuggestions={editorSuggestions.mentionSuggestions} mentionHighlights={editorSuggestions.mentionHighlights} /> @@ -158,7 +155,7 @@ export const IssueCommentCard: React.FC = (props) => { )} diff --git a/web/components/issues/issue-peek-overview/activity/comment-editor.tsx b/web/components/issues/peek-overview/activity/comment-editor.tsx similarity index 90% rename from web/components/issues/issue-peek-overview/activity/comment-editor.tsx rename to web/components/issues/peek-overview/activity/comment-editor.tsx index 6793c2daf..a53e4160f 100644 --- a/web/components/issues/issue-peek-overview/activity/comment-editor.tsx +++ b/web/components/issues/peek-overview/activity/comment-editor.tsx @@ -11,16 +11,16 @@ import { LiteTextEditorWithRef } from "@plane/lite-text-editor"; // ui import { Button } from "@plane/ui"; // types -import type { IIssueComment } from "types"; +import type { IIssueActivity } from "types"; -const defaultValues: Partial = { +const defaultValues: Partial = { access: "INTERNAL", comment_html: "", }; type IIssueCommentEditor = { disabled?: boolean; - onSubmit: (data: IIssueComment) => Promise; + onSubmit: (data: IIssueActivity) => Promise; showAccessSpecifier?: boolean; }; @@ -60,9 +60,9 @@ export const IssueCommentEditor: React.FC = (props) => { formState: { isSubmitting }, handleSubmit, reset, - } = useForm({ defaultValues }); + } = useForm({ defaultValues }); - const handleAddComment = async (formData: IIssueComment) => { + const handleAddComment = async (formData: IIssueActivity) => { if (!formData.comment_html || isSubmitting) return; await onSubmit(formData).then(() => { @@ -99,7 +99,7 @@ export const IssueCommentEditor: React.FC = (props) => { onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)} commentAccessSpecifier={ showAccessSpecifier - ? { accessValue, onAccessChange, showAccessSpecifier, commentAccess } + ? { accessValue: accessValue ?? "INTERNAL", onAccessChange, showAccessSpecifier, commentAccess } : undefined } submitButton={ diff --git a/web/components/issues/issue-peek-overview/activity/comment-reaction.tsx b/web/components/issues/peek-overview/activity/comment-reaction.tsx similarity index 95% rename from web/components/issues/issue-peek-overview/activity/comment-reaction.tsx rename to web/components/issues/peek-overview/activity/comment-reaction.tsx index 46fbae50b..144252dc9 100644 --- a/web/components/issues/issue-peek-overview/activity/comment-reaction.tsx +++ b/web/components/issues/peek-overview/activity/comment-reaction.tsx @@ -2,7 +2,7 @@ import { FC } from "react"; import useSWR from "swr"; import { observer } from "mobx-react-lite"; // components -import { IssueReaction } from "../reactions"; +import { IssuePeekOverviewReactions } from "components/issues"; // hooks import { useMobxStore } from "lib/mobx/store-provider"; // types @@ -49,7 +49,7 @@ export const IssueCommentReaction: FC = observer((props) return (
- void; issueCommentUpdate: (comment: any) => void; issueCommentRemove: (commentId: string) => void; issueCommentReactionCreate: (commentId: string, reaction: string) => void; issueCommentReactionRemove: (commentId: string, reaction: string) => void; showCommentAccessSpecifier: boolean; -} +}; -export const IssueComment: FC = (props) => { +export const IssueActivity: FC = (props) => { const { workspaceSlug, projectId, issueId, user, - issueComments, + issueActivity, issueCommentCreate, issueCommentUpdate, issueCommentRemove, @@ -47,7 +48,7 @@ export const IssueComment: FC = (props) => { projectId={projectId} issueId={issueId} user={user} - issueComments={issueComments} + issueActivity={issueActivity} issueCommentUpdate={issueCommentUpdate} issueCommentRemove={issueCommentRemove} issueCommentReactionCreate={issueCommentReactionCreate} diff --git a/web/components/issues/peek-overview/index.ts b/web/components/issues/peek-overview/index.ts new file mode 100644 index 000000000..38581dada --- /dev/null +++ b/web/components/issues/peek-overview/index.ts @@ -0,0 +1,6 @@ +export * from "./activity"; +export * from "./reactions"; +export * from "./issue-detail"; +export * from "./properties"; +export * from "./root"; +export * from "./view"; diff --git a/web/components/issues/issue-peek-overview/issue-detail.tsx b/web/components/issues/peek-overview/issue-detail.tsx similarity index 94% rename from web/components/issues/issue-peek-overview/issue-detail.tsx rename to web/components/issues/peek-overview/issue-detail.tsx index ac156180c..bc9e4c1d9 100644 --- a/web/components/issues/issue-peek-overview/issue-detail.tsx +++ b/web/components/issues/peek-overview/issue-detail.tsx @@ -1,19 +1,22 @@ import { ChangeEvent, FC, useCallback, useEffect, useState } from "react"; import { Controller, useForm } from "react-hook-form"; +import debounce from "lodash/debounce"; // packages import { RichTextEditor } from "@plane/rich-text-editor"; -// components -import { TextArea } from "@plane/ui"; -import { IssueReaction } from "./reactions"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; // hooks -import debounce from "lodash/debounce"; import useReloadConfirmations from "hooks/use-reload-confirmation"; import useEditorSuggestions from "hooks/use-editor-suggestions"; +// components +import { IssuePeekOverviewReactions } from "components/issues"; +// ui +import { TextArea } from "@plane/ui"; // types -import { IIssue } from "types"; +import { IIssue, IUser } from "types"; // services import { FileService } from "services/file.service"; -import { useMobxStore } from "lib/mobx/store-provider"; +// constants import { EUserWorkspaceRoles } from "constants/workspace"; const fileService = new FileService(); @@ -22,7 +25,7 @@ interface IPeekOverviewIssueDetails { workspaceSlug: string; issue: IIssue; issueReactions: any; - user: any; + user: IUser | null; issueUpdate: (issue: Partial) => void; issueReactionCreate: (reaction: string) => void; issueReactionRemove: (reaction: string) => void; @@ -89,7 +92,7 @@ export const PeekOverviewIssueDetails: FC = (props) = setLocalIssueDescription({ id: issue.id, description_html: issue.description_html }); setLocalTitleValue(issue.name); } - }, [issue.id]); + }, [issue.id, issue.description_html, issue.name]); const debouncedFormSave = debounce(async () => { handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted")); @@ -104,7 +107,7 @@ export const PeekOverviewIssueDetails: FC = (props) = } else if (isSubmitting === "submitting") { setShowAlert(true); } - }, [isSubmitting, setShowAlert]); + }, [isSubmitting, setShowAlert, setIsSubmitting]); // reset form values useEffect(() => { @@ -165,7 +168,7 @@ export const PeekOverviewIssueDetails: FC = (props) = ( + render={({ field: { onChange } }) => ( = (props) = )} />
- = observer((pro const { user: { currentProjectRole }, - cycleIssues: cycleIssueStore, - moduleIssues: { addIssueToModule }, issueDetail: { fetchPeekIssueDetails }, } = useMobxStore(); diff --git a/web/components/issues/issue-peek-overview/reactions/index.ts b/web/components/issues/peek-overview/reactions/index.ts similarity index 100% rename from web/components/issues/issue-peek-overview/reactions/index.ts rename to web/components/issues/peek-overview/reactions/index.ts index a65262eb7..579646533 100644 --- a/web/components/issues/issue-peek-overview/reactions/index.ts +++ b/web/components/issues/peek-overview/reactions/index.ts @@ -1,3 +1,3 @@ +export * from "./preview"; export * from "./root"; export * from "./selector"; -export * from "./preview"; diff --git a/web/components/issues/issue-peek-overview/reactions/preview.tsx b/web/components/issues/peek-overview/reactions/preview.tsx similarity index 100% rename from web/components/issues/issue-peek-overview/reactions/preview.tsx rename to web/components/issues/peek-overview/reactions/preview.tsx diff --git a/web/components/issues/issue-peek-overview/reactions/root.tsx b/web/components/issues/peek-overview/reactions/root.tsx similarity index 80% rename from web/components/issues/issue-peek-overview/reactions/root.tsx rename to web/components/issues/peek-overview/reactions/root.tsx index efa2e488c..39e1cc407 100644 --- a/web/components/issues/issue-peek-overview/reactions/root.tsx +++ b/web/components/issues/peek-overview/reactions/root.tsx @@ -1,16 +1,18 @@ import { FC } from "react"; // components -import { IssueReactionPreview, IssueReactionSelector } from "./"; +import { IssueReactionPreview, IssueReactionSelector } from "components/issues"; +// types +import { IUser } from "types"; interface IIssueReaction { issueReactions: any; - user: any; + user: IUser | null; issueReactionCreate: (reaction: string) => void; issueReactionRemove: (reaction: string) => void; position?: "top" | "bottom"; } -export const IssueReaction: FC = (props) => { +export const IssuePeekOverviewReactions: FC = (props) => { const { issueReactions, user, issueReactionCreate, issueReactionRemove, position = "bottom" } = props; const handleReaction = (reaction: string) => { diff --git a/web/components/issues/issue-peek-overview/reactions/selector.tsx b/web/components/issues/peek-overview/reactions/selector.tsx similarity index 100% rename from web/components/issues/issue-peek-overview/reactions/selector.tsx rename to web/components/issues/peek-overview/reactions/selector.tsx diff --git a/web/components/issues/issue-peek-overview/root.tsx b/web/components/issues/peek-overview/root.tsx similarity index 52% rename from web/components/issues/issue-peek-overview/root.tsx rename to web/components/issues/peek-overview/root.tsx index e9d0ecd3e..5812aac63 100644 --- a/web/components/issues/issue-peek-overview/root.tsx +++ b/web/components/issues/peek-overview/root.tsx @@ -1,17 +1,17 @@ -import { FC, Fragment, ReactNode, useEffect } from "react"; +import { FC, Fragment, ReactNode, useCallback, useEffect } from "react"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; -import useSWR from "swr"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; // hooks import useToast from "hooks/use-toast"; // components -import { IssueView } from "./view"; +import { IssueView } from "components/issues"; // helpers import { copyUrlToClipboard } from "helpers/string.helper"; // types import { IIssue } from "types"; +// constants import { EUserWorkspaceRoles } from "constants/workspace"; interface IIssuePeekOverview { @@ -30,27 +30,45 @@ export const IssuePeekOverview: FC = observer((props) => { const { peekIssueId } = router.query; const { - user: userStore, - issue: issueStore, - issueDetail: issueDetailStore, - archivedIssueDetail: archivedIssueDetailStore, - archivedIssues: archivedIssuesStore, - project: projectStore, + user: { currentProjectRole }, + issue: { removeIssueFromStructure }, + issueDetail: { + createIssueComment, + updateIssueComment, + removeIssueComment, + creationIssueCommentReaction, + removeIssueCommentReaction, + createIssueReaction, + removeIssueReaction, + createIssueSubscription, + removeIssueSubscription, + getIssue, + loader, + fetchPeekIssueDetails, + setPeekId, + fetchIssueActivity, + }, + archivedIssueDetail: { + getIssue: getArchivedIssue, + loader: archivedIssueLoader, + fetchPeekIssueDetails: fetchArchivedPeekIssueDetails, + }, + archivedIssues: { deleteArchivedIssue }, + project: { currentProjectDetails }, } = useMobxStore(); const { setToastAlert } = useToast(); - const fetchIssueDetail = async () => { + const fetchIssueDetail = useCallback(async () => { if (workspaceSlug && projectId && peekIssueId) { - if (isArchived) - await archivedIssueDetailStore.fetchPeekIssueDetails(workspaceSlug, projectId, peekIssueId as string); - else await issueDetailStore.fetchPeekIssueDetails(workspaceSlug, projectId, peekIssueId as string); + if (isArchived) await fetchArchivedPeekIssueDetails(workspaceSlug, projectId, peekIssueId as string); + else await fetchPeekIssueDetails(workspaceSlug, projectId, peekIssueId as string); } - }; + }, [fetchArchivedPeekIssueDetails, fetchPeekIssueDetails, workspaceSlug, projectId, peekIssueId, isArchived]); useEffect(() => { fetchIssueDetail(); - }, [workspaceSlug, projectId, peekIssueId]); + }, [workspaceSlug, projectId, peekIssueId, fetchIssueDetail]); const handleCopyText = (e: React.MouseEvent) => { e.stopPropagation(); @@ -72,44 +90,43 @@ export const IssuePeekOverview: FC = observer((props) => { }); }; - const issue = isArchived ? archivedIssueDetailStore.getIssue : issueDetailStore.getIssue; - const isLoading = isArchived ? archivedIssueDetailStore.loader : issueDetailStore.loader; + const issue = isArchived ? getArchivedIssue : getIssue; + const isLoading = isArchived ? archivedIssueLoader : loader; - const issueUpdate = (_data: Partial) => { - if (handleIssue) handleIssue(_data); + const issueUpdate = async (_data: Partial) => { + if (handleIssue) { + await handleIssue(_data); + fetchIssueActivity(workspaceSlug, projectId, issueId); + } }; - const issueReactionCreate = (reaction: string) => - issueDetailStore.createIssueReaction(workspaceSlug, projectId, issueId, reaction); + const issueReactionCreate = (reaction: string) => createIssueReaction(workspaceSlug, projectId, issueId, reaction); - const issueReactionRemove = (reaction: string) => - issueDetailStore.removeIssueReaction(workspaceSlug, projectId, issueId, reaction); + const issueReactionRemove = (reaction: string) => removeIssueReaction(workspaceSlug, projectId, issueId, reaction); - const issueCommentCreate = (comment: any) => - issueDetailStore.createIssueComment(workspaceSlug, projectId, issueId, comment); + const issueCommentCreate = (comment: any) => createIssueComment(workspaceSlug, projectId, issueId, comment); const issueCommentUpdate = (comment: any) => - issueDetailStore.updateIssueComment(workspaceSlug, projectId, issueId, comment?.id, comment); + updateIssueComment(workspaceSlug, projectId, issueId, comment?.id, comment); - const issueCommentRemove = (commentId: string) => - issueDetailStore.removeIssueComment(workspaceSlug, projectId, issueId, commentId); + const issueCommentRemove = (commentId: string) => removeIssueComment(workspaceSlug, projectId, issueId, commentId); const issueCommentReactionCreate = (commentId: string, reaction: string) => - issueDetailStore.creationIssueCommentReaction(workspaceSlug, projectId, issueId, commentId, reaction); + creationIssueCommentReaction(workspaceSlug, projectId, issueId, commentId, reaction); const issueCommentReactionRemove = (commentId: string, reaction: string) => - issueDetailStore.removeIssueCommentReaction(workspaceSlug, projectId, issueId, commentId, reaction); + removeIssueCommentReaction(workspaceSlug, projectId, issueId, commentId, reaction); - const issueSubscriptionCreate = () => issueDetailStore.createIssueSubscription(workspaceSlug, projectId, issueId); + const issueSubscriptionCreate = () => createIssueSubscription(workspaceSlug, projectId, issueId); - const issueSubscriptionRemove = () => issueDetailStore.removeIssueSubscription(workspaceSlug, projectId, issueId); + const issueSubscriptionRemove = () => removeIssueSubscription(workspaceSlug, projectId, issueId); const handleDeleteIssue = async () => { - if (isArchived) await archivedIssuesStore.deleteArchivedIssue(workspaceSlug, projectId, issue!); - else await issueStore.removeIssueFromStructure(workspaceSlug, projectId, issue!); + if (isArchived) await deleteArchivedIssue(workspaceSlug, projectId, issue!); + else removeIssueFromStructure(workspaceSlug, projectId, issue!); const { query } = router; if (query.peekIssueId) { - issueDetailStore.setPeekId(null); + setPeekId(null); delete query.peekIssueId; delete query.peekProjectId; router.push({ @@ -119,7 +136,7 @@ export const IssuePeekOverview: FC = observer((props) => { } }; - const userRole = userStore.currentProjectRole ?? EUserWorkspaceRoles.GUEST; + const userRole = currentProjectRole ?? EUserWorkspaceRoles.GUEST; return ( @@ -144,7 +161,7 @@ export const IssuePeekOverview: FC = observer((props) => { issueSubscriptionRemove={issueSubscriptionRemove} handleDeleteIssue={handleDeleteIssue} disableUserActions={[5, 10].includes(userRole)} - showCommentAccessSpecifier={projectStore.currentProjectDetails?.is_deployed} + showCommentAccessSpecifier={currentProjectDetails?.is_deployed} > {children} diff --git a/web/components/issues/issue-peek-overview/view.tsx b/web/components/issues/peek-overview/view.tsx similarity index 89% rename from web/components/issues/issue-peek-overview/view.tsx rename to web/components/issues/peek-overview/view.tsx index a05ec9ac1..d800b8681 100644 --- a/web/components/issues/issue-peek-overview/view.tsx +++ b/web/components/issues/peek-overview/view.tsx @@ -3,16 +3,21 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import useSWR from "swr"; import { MoveRight, MoveDiagonal, Bell, Link2, Trash2 } from "lucide-react"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; // components -import { PeekOverviewIssueDetails } from "./issue-detail"; -import { PeekOverviewProperties } from "./properties"; -import { IssueComment } from "./activity"; +import { + DeleteArchivedIssueModal, + DeleteIssueModal, + IssueActivity, + IssueUpdateStatus, + PeekOverviewIssueDetails, + PeekOverviewProperties, +} from "components/issues"; +// ui import { Button, CenterPanelIcon, CustomSelect, FullScreenPanelIcon, SidePanelIcon, Spinner } from "@plane/ui"; -import { DeleteIssueModal, DeleteArchivedIssueModal, IssueUpdateStatus } from "components/issues/"; // types import { IIssue } from "types"; -// hooks -import { useMobxStore } from "lib/mobx/store-provider"; interface IIssueView { workspaceSlug: string; @@ -41,7 +46,7 @@ interface IIssueView { type TPeekModes = "side-peek" | "modal" | "full-screen"; -const peekOptions: { key: TPeekModes; icon: any; title: string }[] = [ +const PEEK_OPTIONS: { key: TPeekModes; icon: any; title: string }[] = [ { key: "side-peek", icon: SidePanelIcon, @@ -86,9 +91,12 @@ export const IssueView: FC = observer((props) => { } = props; const router = useRouter(); - const { peekIssueId } = router.query as { peekIssueId: string }; + const { peekIssueId } = router.query; - const { user: userStore, issueDetail: issueDetailStore } = useMobxStore(); + const { + user: { currentUser }, + issueDetail: { fetchIssueSubscription, getIssueActivity, getIssueReactions, getIssueSubscription, setPeekId }, + } = useMobxStore(); const [peekMode, setPeekMode] = useState("side-peek"); const [deleteIssueModal, setDeleteIssueModal] = useState(false); @@ -96,7 +104,7 @@ export const IssueView: FC = observer((props) => { const updateRoutePeekId = () => { if (issueId != peekIssueId) { - issueDetailStore.setPeekId(issueId); + setPeekId(issueId); const { query } = router; router.push({ pathname: router.pathname, @@ -104,10 +112,13 @@ export const IssueView: FC = observer((props) => { }); } }; + const removeRoutePeekId = () => { const { query } = router; + if (query.peekIssueId) { - issueDetailStore.setPeekId(null); + setPeekId(null); + delete query.peekIssueId; delete query.peekProjectId; router.push({ @@ -123,18 +134,16 @@ export const IssueView: FC = observer((props) => { : null, async () => { if (workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId) { - await issueDetailStore.fetchIssueSubscription(workspaceSlug, projectId, issueId); + await fetchIssueSubscription(workspaceSlug, projectId, issueId); } } ); - const issueReactions = issueDetailStore.getIssueReactions || []; - const issueComments = issueDetailStore.getIssueComments || []; - const issueSubscription = issueDetailStore.getIssueSubscription || []; + const issueReactions = getIssueReactions || []; + const issueActivity = getIssueActivity; + const issueSubscription = getIssueSubscription || []; - const user = userStore?.currentUser; - - const currentMode = peekOptions.find((m) => m.key === peekMode); + const currentMode = PEEK_OPTIONS.find((m) => m.key === peekMode); return ( <> @@ -198,7 +207,7 @@ export const IssueView: FC = observer((props) => { } > - {peekOptions.map((mode) => ( + {PEEK_OPTIONS.map((mode) => (
= observer((props) => {
- {issue?.created_by !== user?.id && - !issue?.assignees.includes(user?.id ?? "") && + {issue?.created_by !== currentUser?.id && + !issue?.assignees.includes(currentUser?.id ?? "") && !router.pathname.includes("[archivedIssueId]") && (