fix: peek over data fetching fixes

This commit is contained in:
sriramveeraghanta 2023-08-31 00:12:45 +05:30
parent a27edad810
commit 6246a740d5
12 changed files with 262 additions and 199 deletions

View File

@ -14,7 +14,7 @@ import { IIssue } from "types/issue";
import { RootStore } from "store/root";
export const IssueListBlock = observer(({ issue }: { issue: IIssue }) => {
const { issue: issueStore, project: projectStore }: RootStore = useMobxStore();
const { issue: issueStore, project: projectStore, issueDetails: issueDetailStore }: RootStore = useMobxStore();
return (
<div className="flex items-center px-9 py-3.5 relative gap-10 border-b border-custom-border-200 bg-custom-background-100 last:border-b-0">
@ -27,7 +27,7 @@ export const IssueListBlock = observer(({ issue }: { issue: IIssue }) => {
<div className="h-full line-clamp-1 w-full overflow-ellipsis cursor-pointer">
<p
onClick={() => {
issueStore.setPeekId(issue.id);
issueDetailStore.setPeekId(issue.id);
}}
className="text-[0.825rem] font-medium text-sm truncate text-custom-text-100"
>

View File

@ -1,70 +1,52 @@
import { useEffect } from "react";
// mobx
import { observer } from "mobx-react-lite";
// lib
import { useMobxStore } from "lib/mobx/store-provider";
// components
import {
PeekOverviewHeader,
PeekOverviewIssueActivity,
PeekOverviewIssueDetails,
PeekOverviewIssueProperties,
TPeekOverviewModes,
} from "components/issues/peek-overview";
// types
import { IIssue } from "types/issue";
type Props = {
issueId: string;
workspaceSlug: string;
projectId: string;
handleClose: () => void;
mode: TPeekOverviewModes;
setMode: (mode: TPeekOverviewModes) => void;
issueDetails: IIssue;
};
export const FullScreenPeekView: React.FC<Props> = observer((props) => {
const { handleClose, issueId, mode, setMode, workspaceSlug , projectId } = props;
const { handleClose, issueDetails } = props;
const { issue: issueStore } = useMobxStore();
const issue = issueStore.issue_detail[issueId]?.issue;
useEffect(() => {
if (!workspaceSlug || !projectId || !issueId) return;
issueStore.getIssueByIdAsync(workspaceSlug, projectId, issueId);
}, [workspaceSlug, projectId, issueId, issueStore]);
const { issueDetails: issueDetailStore } = useMobxStore();
return (
<div className="h-full w-full grid grid-cols-10 divide-x divide-custom-border-200 overflow-hidden">
<div className="h-full w-full flex flex-col col-span-7 overflow-hidden">
<div className="w-full p-5">
<PeekOverviewHeader
handleClose={handleClose}
issue={issue}
mode={mode}
setMode={setMode}
workspaceSlug={workspaceSlug}
/>
</div>
<div className="h-full w-full px-6 overflow-y-auto">
{/* issue title and description */}
<div className="w-full">
<PeekOverviewIssueDetails issue={issue} />
</div>
{/* divider */}
<div className="h-[1] w-full border-t border-custom-border-200 my-5" />
{/* issue activity/comments */}
<div className="w-full">
<PeekOverviewIssueActivity workspaceSlug={workspaceSlug} />
</div>
</div>
</div>
<div className="col-span-3 h-full w-full overflow-y-auto">
{/* issue properties */}
<div className="w-full px-6 py-5">
<PeekOverviewIssueProperties issue={issue} mode="full" workspaceSlug={workspaceSlug} />
</div>
</div>
<div className="h-full w-full flex flex-col col-span-7 overflow-hidden">
<div className="w-full p-5">
<PeekOverviewHeader handleClose={handleClose} issueDetails={issueDetails} />
</div>
<div className="h-full w-full px-6 overflow-y-auto">
{/* issue title and description */}
<div className="w-full">
<PeekOverviewIssueDetails issueDetails={issueDetails} />
</div>
)
})
{/* divider */}
<div className="h-[1] w-full border-t border-custom-border-200 my-5" />
{/* issue activity/comments */}
<div className="w-full">
<PeekOverviewIssueActivity issueDetails={issueDetails} />
</div>
</div>
</div>
<div className="col-span-3 h-full w-full overflow-y-auto">
{/* issue properties */}
<div className="w-full px-6 py-5">
<PeekOverviewIssueProperties issueDetails={issueDetails} mode="full" />
</div>
</div>
</div>
);
});

View File

@ -1,23 +1,26 @@
import { useRouter } from "next/router";
import { ArrowRightAlt, CloseFullscreen, East, OpenInFull } from "@mui/icons-material";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Icon } from "components/ui";
// helpers
import { copyTextToClipboard } from "helpers/string.helper";
// store
import { IPeekMode } from "store/issue_details";
import { RootStore } from "store/root";
// lib
import { useMobxStore } from "lib/mobx/store-provider";
// types
import { TPeekOverviewModes } from "./layout";
import { ArrowRightAlt, CloseFullscreen, East, OpenInFull } from "@mui/icons-material";
import { IIssue } from "types";
type Props = {
handleClose: () => void;
issue: any;
mode: TPeekOverviewModes;
setMode: (mode: TPeekOverviewModes) => void;
workspaceSlug: string;
issueDetails: IIssue;
};
const peekModes: {
key: TPeekOverviewModes;
key: IPeekMode;
icon: string;
label: string;
}[] = [
@ -34,13 +37,20 @@ const peekModes: {
},
];
export const PeekOverviewHeader: React.FC<Props> = ({ issue, handleClose, mode, setMode, workspaceSlug }) => {
export const PeekOverviewHeader: React.FC<Props> = (props) => {
const { issueDetails, handleClose } = props;
const { issueDetails: issueDetailStore }: RootStore = useMobxStore();
const router = useRouter();
const { workspaceSlug } = router.query;
const { setToastAlert } = useToast();
const handleCopyLink = () => {
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${issue.project}/`).then(() => {
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${issueDetails.project}/`).then(() => {
setToastAlert({
type: "success",
title: "Link copied!",
@ -52,7 +62,7 @@ export const PeekOverviewHeader: React.FC<Props> = ({ issue, handleClose, mode,
return (
<div className="flex justify-between items-center">
<div className="flex items-center gap-4">
{mode === "side" && (
{issueDetailStore.peekMode === "side" && (
<button
type="button"
onClick={() => {
@ -66,8 +76,8 @@ export const PeekOverviewHeader: React.FC<Props> = ({ issue, handleClose, mode,
/>
</button>
)}
{mode === "modal" || mode === "full" ? (
<button type="button" onClick={() => setMode("side")}>
{issueDetailStore.peekMode === "modal" || issueDetailStore.peekMode === "full" ? (
<button type="button" onClick={() => issueDetailStore.setPeekMode("side")}>
<CloseFullscreen
sx={{
fontSize: "14px",
@ -75,7 +85,7 @@ export const PeekOverviewHeader: React.FC<Props> = ({ issue, handleClose, mode,
/>
</button>
) : (
<button type="button" onClick={() => setMode("modal")}>
<button type="button" onClick={() => issueDetailStore.setPeekMode("modal")}>
<OpenInFull
sx={{
fontSize: "14px",
@ -83,11 +93,14 @@ export const PeekOverviewHeader: React.FC<Props> = ({ issue, handleClose, mode,
/>
</button>
)}
<button type="button" className={`grid place-items-center ${mode === "full" ? "rotate-45" : ""}`}>
<Icon iconName={peekModes.find((m) => m.key === mode)?.icon ?? ""} />
<button
type="button"
className={`grid place-items-center ${issueDetailStore.peekMode === "full" ? "rotate-45" : ""}`}
>
<Icon iconName={peekModes.find((m) => m.key === issueDetailStore.peekMode)?.icon ?? ""} />
</button>
</div>
{(mode === "side" || mode === "modal") && (
{(issueDetailStore.peekMode === "side" || issueDetailStore.peekMode === "modal") && (
<div className="flex items-center gap-2">
<button type="button" onClick={handleCopyLink} className="-rotate-45">
<Icon iconName="link" />

View File

@ -1,42 +1,41 @@
import React, { useEffect } from "react";
// mobx
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
// lib
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { CommentCard, AddComment } from "components/issues/peek-overview";
// types
import { IIssue } from "types";
type Props = {
workspaceSlug: string;
issueDetails: IIssue;
};
export const PeekOverviewIssueActivity: React.FC<Props> = observer((props) => {
const { workspaceSlug } = props;
const router = useRouter();
const { workspaceSlug } = router.query;
const { issue: issueStore, user: userStore } = useMobxStore();
const { issueDetails: issueDetailStore, user: userStore } = useMobxStore();
const issueId = issueStore?.activePeekOverviewIssueId;
const comments = issueStore?.issue_detail[issueId ?? ""]?.comments ?? [];
useEffect(() => {
if (userStore.currentUser) return;
userStore.getUserAsync();
}, [userStore]);
const issueId = issueDetailStore?.peekId;
const comments = issueDetailStore?.details[issueId ?? ""]?.comments ?? [];
return (
<div>
<h4 className="font-medium">Activity</h4>
<div className="mt-4">
<div className="space-y-4">
{comments.map((comment) => (
<CommentCard comment={comment} workspaceSlug={workspaceSlug} />
))}
</div>
{workspaceSlug && (
<div className="mt-4">
<AddComment disabled={!userStore.currentUser} issueId={issueId} />
<div className="space-y-4">
{comments.map((comment: any) => (
<CommentCard comment={comment} workspaceSlug={workspaceSlug?.toString()} />
))}
</div>
<div className="mt-4">
<AddComment disabled={!userStore.currentUser} issueId={issueId} />
</div>
</div>
</div>
)}
</div>
);
});

View File

@ -4,15 +4,15 @@ import { IssueReactions } from "components/issues/peek-overview";
import { IIssue } from "types";
type Props = {
issue: IIssue;
issueDetails: IIssue;
};
export const PeekOverviewIssueDetails: React.FC<Props> = ({ issue }) => (
export const PeekOverviewIssueDetails: React.FC<Props> = ({ issueDetails }) => (
<div className="space-y-2">
<h6 className="font-medium text-custom-text-200">
{issue.project_detail.identifier}-{issue.sequence_id}
{issueDetails.project_detail.identifier}-{issueDetails.sequence_id}
</h6>
<h4 className="break-words text-2xl font-semibold">{issue.name}</h4>
<h4 className="break-words text-2xl font-semibold">{issueDetails.name}</h4>
<IssueReactions />
</div>
);

View File

@ -3,24 +3,23 @@ import { Disclosure } from "@headlessui/react";
// import { getStateGroupIcon } from "components/icons";
// hooks
import useToast from "hooks/use-toast";
// components
import { TPeekOverviewModes } from "components/issues/peek-overview";
// icons
import { Icon } from "components/ui";
import { copyTextToClipboard, addSpaceIfCamelCase } from "helpers/string.helper";
// types
import { IIssue } from "types";
// constants
import { issueGroupFilter, issuePriorityFilter } from "constants/data";
import { useEffect } from "react";
import { renderDateFormat } from "constants/helpers";
import { IPeekMode } from "store/issue_details";
import { useRouter } from "next/router";
import { RootStore } from "store/root";
import { useMobxStore } from "lib/mobx/store-provider";
type Props = {
issue: IIssue;
mode: TPeekOverviewModes;
workspaceSlug: string;
issueDetails: IIssue;
mode?: IPeekMode;
};
const validDate = (date: any, state: string): string => {
@ -35,11 +34,16 @@ const validDate = (date: any, state: string): string => {
}
};
export const PeekOverviewIssueProperties: React.FC<Props> = ({ issue, mode, workspaceSlug }) => {
export const PeekOverviewIssueProperties: React.FC<Props> = ({ issueDetails, mode }) => {
const { setToastAlert } = useToast();
const startDate = issue.start_date;
const targetDate = issue.target_date;
const { issueDetails: issueDetailStore }: RootStore = useMobxStore();
const router = useRouter();
const { workspaceSlug } = router.query;
const startDate = issueDetails.start_date;
const targetDate = issueDetails.target_date;
const minDate = startDate ? new Date(startDate) : null;
minDate?.setDate(minDate.getDate());
@ -47,15 +51,17 @@ export const PeekOverviewIssueProperties: React.FC<Props> = ({ issue, mode, work
const maxDate = targetDate ? new Date(targetDate) : null;
maxDate?.setDate(maxDate.getDate());
const state = issue.state_detail;
const state = issueDetails.state_detail;
const stateGroup = issueGroupFilter(state.group);
const priority = issue.priority ? issuePriorityFilter(issue.priority) : null;
const priority = issueDetails.priority ? issuePriorityFilter(issueDetails.priority) : null;
const handleCopyLink = () => {
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`).then(() => {
copyTextToClipboard(
`${originURL}/${workspaceSlug}/projects/${issueDetails.project}/issues/${issueDetails.id}`
).then(() => {
setToastAlert({
type: "success",
title: "Link copied!",
@ -70,7 +76,7 @@ export const PeekOverviewIssueProperties: React.FC<Props> = ({ issue, mode, work
<div className="flex justify-between gap-2 pb-3">
<h6 className="flex items-center gap-2 font-medium">
{/* {getStateGroupIcon(issue.state_detail.group, "16", "16", issue.state_detail.color)} */}
{issue.project_detail.identifier}-{issue.sequence_id}
{issueDetails.project_detail.identifier}-{issueDetails.sequence_id}
</h6>
<div className="flex items-center gap-2">
<button type="button" onClick={handleCopyLink} className="-rotate-45">
@ -131,12 +137,12 @@ export const PeekOverviewIssueProperties: React.FC<Props> = ({ issue, mode, work
<span className="flex-grow truncate">Due date</span>
</div>
<div>
{issue.target_date ? (
{issueDetails.target_date ? (
<div
className={`h-[24px] rounded-md flex px-2.5 py-1 items-center border border-custom-border-100 gap-1 text-custom-text-100 text-xs font-medium
${validDate(issue.target_date, state)}`}
${validDate(issueDetails.target_date, state)}`}
>
{renderDateFormat(issue.target_date)}
{renderDateFormat(issueDetails.target_date)}
</div>
) : (
<span className="text-custom-text-200">Empty</span>

View File

@ -1,36 +1,48 @@
import React, { useState } from "react";
// headless ui
import React, { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { Dialog, Transition } from "@headlessui/react";
import { observer } from "mobx-react-lite";
// components
import { FullScreenPeekView, SidePeekView } from "components/issues/peek-overview";
// types
import type { IIssue } from "types";
import type { IIssue } from "types/issue";
// lib
import { useMobxStore } from "lib/mobx/store-provider";
type Props = {
issue: IIssue | null;
isOpen: boolean;
onClose: () => void;
workspaceSlug: string;
};
export type TPeekOverviewModes = "side" | "modal" | "full";
export const IssuePeekOverview: React.FC<Props> = observer((props) => {
const { isOpen, onClose } = props;
// router
const router = useRouter();
const { workspace_slug, project_slug } = router.query;
// store
const { issueDetails: issueDetailStore } = useMobxStore();
export const IssuePeekOverview: React.FC<Props> = ({ issue, isOpen, onClose, workspaceSlug }) => {
const [peekOverviewMode, setPeekOverviewMode] = useState<TPeekOverviewModes>("side");
const issueDetails = issueDetailStore.peekId ? issueDetailStore.details[issueDetailStore.peekId] : null;
console.log("issueDetails", issueDetails);
useEffect(() => {
if (workspace_slug && project_slug && issueDetailStore.peekId) {
if (!issueDetails) {
issueDetailStore.fetchIssueDetails(workspace_slug.toString(), project_slug.toString(), issueDetailStore.peekId);
}
}
}, [workspace_slug, project_slug, issueDetailStore, issueDetails]);
const handleClose = () => {
onClose();
setPeekOverviewMode("side");
issueDetailStore.setPeekMode("side");
};
if (!issue || !isOpen) return null;
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
{/* add backdrop conditionally */}
{(peekOverviewMode === "modal" || peekOverviewMode === "full") && (
{(issueDetailStore.peekMode === "modal" || issueDetailStore.peekMode === "full") && (
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -56,32 +68,18 @@ export const IssuePeekOverview: React.FC<Props> = ({ issue, isOpen, onClose, wor
>
<Dialog.Panel
className={`absolute z-20 bg-custom-background-100 ${
peekOverviewMode === "side"
issueDetailStore.peekMode === "side"
? "top-0 right-0 h-full w-1/2 shadow-custom-shadow-md"
: peekOverviewMode === "modal"
: issueDetailStore.peekMode === "modal"
? "top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 h-[70%] w-3/5 rounded-lg shadow-custom-shadow-xl"
: "top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 h-[95%] w-[95%] rounded-lg shadow-custom-shadow-xl"
}`}
>
{(peekOverviewMode === "side" || peekOverviewMode === "modal") && (
<SidePeekView
handleClose={handleClose}
issueId={issue.id}
projectId={issue.project}
mode={peekOverviewMode}
setMode={(mode) => setPeekOverviewMode(mode)}
workspaceSlug={workspaceSlug}
/>
{(issueDetailStore.peekMode === "side" || issueDetailStore.peekMode === "modal") && (
<SidePeekView handleClose={handleClose} issueDetails={issueDetails} />
)}
{peekOverviewMode === "full" && (
<FullScreenPeekView
issueId={issue.id}
workspaceSlug={workspaceSlug}
projectId={issue.project}
handleClose={handleClose}
mode={peekOverviewMode}
setMode={(mode) => setPeekOverviewMode(mode)}
/>
{issueDetailStore.peekMode === "full" && (
<FullScreenPeekView handleClose={handleClose} issueDetails={issueDetails} />
)}
</Dialog.Panel>
</Transition.Child>
@ -90,4 +88,4 @@ export const IssuePeekOverview: React.FC<Props> = ({ issue, isOpen, onClose, wor
</Dialog>
</Transition.Root>
);
};
});

View File

@ -1,64 +1,45 @@
// mobx
import { useEffect } from "react";
import { observer } from "mobx-react-lite";
// lib
import { useMobxStore } from "lib/mobx/store-provider";
// components
import {
PeekOverviewHeader,
PeekOverviewIssueActivity,
PeekOverviewIssueDetails,
PeekOverviewIssueProperties,
TPeekOverviewModes,
} from "components/issues/peek-overview";
import { useEffect } from "react";
// types
import { IIssue } from "types/issue";
type Props = {
issueId: string;
projectId: string;
workspaceSlug: string;
handleClose: () => void;
mode: TPeekOverviewModes;
setMode: (mode: TPeekOverviewModes) => void;
issueDetails: IIssue;
};
export const SidePeekView: React.FC<Props> = observer((props) => {
const { handleClose, issueId, mode, setMode, workspaceSlug, projectId } = props;
const { issue: issueStore } = useMobxStore();
const issue = issueStore.issue_detail[issueId]?.issue;
useEffect(() => {
if (!workspaceSlug || !projectId || !issueId) return;
issueStore.getIssueByIdAsync(workspaceSlug, projectId, issueId);
}, [workspaceSlug, projectId, issueId, issueStore]);
const { handleClose, issueDetails } = props;
return (
<div className="h-full w-full flex flex-col overflow-hidden">
<div className="w-full p-5">
<PeekOverviewHeader
handleClose={handleClose}
issue={issue}
mode={mode}
setMode={setMode}
workspaceSlug={workspaceSlug}
/>
<PeekOverviewHeader handleClose={handleClose} issueDetails={issueDetails} />
</div>
{issue && (
{issueDetails && (
<div className="h-full w-full px-6 overflow-y-auto">
{/* issue title and description */}
<div className="w-full">
<PeekOverviewIssueDetails issue={issue} />
<PeekOverviewIssueDetails issueDetails={issueDetails} />
</div>
{/* issue properties */}
<div className="w-full mt-10">
<PeekOverviewIssueProperties issue={issue} mode={mode} workspaceSlug={workspaceSlug} />
<PeekOverviewIssueProperties issueDetails={issueDetails} />
</div>
{/* divider */}
<div className="h-[1] w-full border-t border-custom-border-200 my-5" />
{/* issue activity/comments */}
<div className="w-full pb-5">
<PeekOverviewIssueActivity workspaceSlug={workspaceSlug} />
<PeekOverviewIssueActivity issueDetails={issueDetails} />
</div>
</div>
)}

View File

@ -16,11 +16,9 @@ export const ProjectDetailsView = observer(() => {
const router = useRouter();
const { workspace_slug, project_slug, states, labels, priorities } = router.query;
const { issue: issueStore, project: projectStore }: RootStore = useMobxStore();
const { issue: issueStore, project: projectStore, issueDetails: issueDetailStore }: RootStore = useMobxStore();
console.log("projectStore?.activeBoard", projectStore?.activeBoard);
const activeIssueId = issueStore.peekId;
const activeIssueId = issueDetailStore.peekId;
useEffect(() => {
if (workspace_slug && project_slug) {
@ -36,12 +34,7 @@ export const ProjectDetailsView = observer(() => {
return (
<div className="relative w-full h-full overflow-hidden">
{workspace_slug && (
<IssuePeekOverview
isOpen={Boolean(activeIssueId)}
onClose={() => issueStore.setPeekId(null)}
issue={issueStore?.issues?.find((_issue) => _issue.id === activeIssueId) || null}
workspaceSlug={workspace_slug.toString()}
/>
<IssuePeekOverview isOpen={Boolean(activeIssueId)} onClose={() => issueDetailStore.setPeekId(null)} />
)}
{issueStore?.loader && !issueStore.issues ? (

View File

@ -18,13 +18,10 @@ export interface IIssueStore {
filteredStates: string[];
filteredLabels: string[];
filteredPriorities: string[];
// peek info
peekId: string | null;
// service
issueService: any;
// actions
fetchPublicIssues: (workspace_slug: string, project_slug: string, params: any) => void;
setPeekId: (issueId: string | null) => void;
getFilteredIssuesByState: (state: string) => IIssue[];
}
@ -42,8 +39,6 @@ class IssueStore implements IIssueStore {
issues: IIssue[] | null = [];
issue_detail: any = {};
peekId: string | null = null;
rootStore: RootStore;
issueService: any;
@ -62,11 +57,8 @@ class IssueStore implements IIssueStore {
// issues
issues: observable.ref,
issue_detail: observable.ref,
// peek
peekId: observable.ref,
// actions
fetchPublicIssues: action,
setPeekId: action,
getFilteredIssuesByState: action,
});
@ -98,10 +90,6 @@ class IssueStore implements IIssueStore {
}
};
setPeekId = (issueId: string | null) => {
this.peekId = issueId;
};
getFilteredIssuesByState = (state_id: string): IIssue[] | [] =>
this.issues?.filter((issue) => issue.state == state_id) || [];
}

View File

@ -0,0 +1,100 @@
import { makeObservable, observable, action, runInAction } from "mobx";
// store
import { RootStore } from "./root";
// services
import IssueService from "services/issue.service";
export type IPeekMode = "side" | "modal" | "full";
export interface IIssueDetailStore {
loader: boolean;
error: any;
// peek info
peekId: string | null;
peekMode: IPeekMode;
details: any;
// actions
setPeekId: (issueId: string | null) => void;
setPeekMode: (mode: IPeekMode) => void;
fetchIssueDetails: (workspaceId: string, projectId: string, issueId: string) => void;
}
class IssueDetailStore implements IssueDetailStore {
loader: boolean = false;
error: any = null;
peekId: string | null = null;
peekMode: IPeekMode = "side";
details: any = {};
issueService: any;
rootStore: RootStore;
constructor(_rootStore: RootStore) {
makeObservable(this, {
loader: observable.ref,
error: observable.ref,
// peek
peekId: observable.ref,
peekMode: observable.ref,
details: observable.ref,
// actions
setPeekId: action,
fetchIssueDetails: action,
setPeekMode: action,
});
this.issueService = new IssueService();
this.rootStore = _rootStore;
}
setPeekId = (issueId: string | null) => {
this.peekId = issueId;
};
setPeekMode = (mode: IPeekMode) => {
this.peekMode = mode;
};
fetchIssueDetails = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
this.loader = true;
this.error = null;
const issueDetails = this.rootStore.issue.issues?.find((i) => i.id === issueId);
const reactionsResponse = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId);
const commentsResponse = await this.issueService.getIssueComments(workspaceSlug, projectId, issueId);
const votesResponse = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId);
if (issueDetails) {
runInAction(() => {
this.details = {
...this.details,
[issueId]: {
...issueDetails,
comments: commentsResponse,
reactions: reactionsResponse,
votes: votesResponse,
},
};
});
}
} catch (error) {
this.loader = false;
this.error = error;
const issueDetails = this.rootStore.issue.issues?.find((i) => i.id === issueId);
runInAction(() => {
this.details = {
...this.details,
[issueId]: {
...issueDetails,
comments: [],
reactions: [],
votes: [],
},
};
});
}
};
}
export default IssueDetailStore;

View File

@ -5,6 +5,7 @@ import UserStore from "./user";
import ThemeStore from "./theme";
import IssueStore, { IIssueStore } from "./issue";
import ProjectStore, { IProjectStore } from "./project";
import IssueDetailStore, { IIssueDetailStore } from "./issue_details";
// types
import { IThemeStore } from "../types";
@ -14,6 +15,7 @@ export class RootStore {
user: UserStore;
theme: IThemeStore;
issue: IIssueStore;
issueDetails: IIssueDetailStore;
project: IProjectStore;
constructor() {
@ -21,5 +23,6 @@ export class RootStore {
this.theme = new ThemeStore(this);
this.issue = new IssueStore(this);
this.project = new ProjectStore(this);
this.issueDetails = new IssueDetailStore(this);
}
}