fix:mobx fixes

This commit is contained in:
sriram veeraghanta 2023-08-30 20:33:21 +05:30
parent 0deed77f1d
commit 579347c991
35 changed files with 699 additions and 595 deletions

View File

@ -1,7 +1,7 @@
"use client";
// types
import { TIssuePriorityKey } from "store/types/issue";
import { TIssuePriorityKey } from "types/issue";
// constants
import { issuePriorityFilter } from "constants/data";

View File

@ -10,7 +10,7 @@ import { IssueBlockState } from "components/issues/board-views/block-state";
import { IssueBlockLabels } from "components/issues/board-views/block-labels";
import { IssueBlockDueDate } from "components/issues/board-views/block-due-date";
// interfaces
import { IIssue } from "store/types/issue";
import { IIssue } from "types/issue";
import { RootStore } from "store/root";
export const IssueListBlock = observer(({ issue }: { issue: IIssue }) => {

View File

@ -3,7 +3,7 @@
// mobx react lite
import { observer } from "mobx-react-lite";
// interfaces
import { IIssueState } from "store/types/issue";
import { IIssueState } from "types/issue";
// constants
import { issueGroupFilter } from "constants/data";
// mobx hook
@ -24,7 +24,7 @@ export const IssueListHeader = observer(({ state }: { state: IIssueState }) => {
</div>
<div className="font-semibold text-base capitalize ml-2 mr-3">{state?.name}</div>
<div className="text-gray-700 w-full max-w-[26px] h-[20px] flex justify-center items-center rounded-full">
{store.issue.getCountOfIssuesByState(state.id)}
{/* {store.issue.getCountOfIssuesByState(state.id)} */}
</div>
</div>
);

View File

@ -6,7 +6,7 @@ import { observer } from "mobx-react-lite";
import { IssueListHeader } from "components/issues/board-views/kanban/header";
import { IssueListBlock } from "components/issues/board-views/kanban/block";
// interfaces
import { IIssueState, IIssue } from "store/types/issue";
import { IIssueState, IIssue } from "types/issue";
// mobx hook
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";

View File

@ -10,24 +10,24 @@ import { IssueBlockDueDate } from "components/issues/board-views/block-due-date"
// mobx hook
import { useMobxStore } from "lib/mobx/store-provider";
// interfaces
import { IIssue } from "store/types/issue";
import { IIssue } from "types/issue";
import { RootStore } from "store/root";
export const IssueListBlock = observer(({ issue }: { issue: IIssue }) => {
const store: RootStore = useMobxStore();
const { issue: issueStore, project: projectStore }: 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">
<div className="relative flex items-center gap-6 w-full flex-grow overflow-hidden">
{/* id */}
<div className="flex-shrink-0 text-sm w-[60px] text-custom-text-200">
{store?.project?.project?.identifier}-{issue?.sequence_id}
<div className="flex-shrink-0 text-sm w-auto text-custom-text-200">
{projectStore?.project?.identifier}-{issue?.sequence_id}
</div>
{/* name */}
<div className="h-full line-clamp-1 w-full overflow-ellipsis cursor-pointer">
<p
onClick={() => {
store.issue.setActivePeekOverviewIssueId(issue.id);
issueStore.setPeekId(issue.id);
}}
className="text-[0.825rem] font-medium text-sm truncate text-custom-text-100"
>

View File

@ -3,7 +3,7 @@
// mobx react lite
import { observer } from "mobx-react-lite";
// interfaces
import { IIssueState } from "store/types/issue";
import { IIssueState } from "types/issue";
// constants
import { issueGroupFilter } from "constants/data";
// mobx hook
@ -23,7 +23,7 @@ export const IssueListHeader = observer(({ state }: { state: IIssueState }) => {
<stateGroup.icon />
</div>
<div className="font-semibold leading-6 text-base capitalize ml-2 mr-3">{state?.name}</div>
<div className="text-gray-700 font-normal text-base">{store.issue.getCountOfIssuesByState(state.id)}</div>
{/* <div className="text-gray-700 font-normal text-base">{store.issue.getCountOfIssuesByState(state.id)}</div> */}
</div>
);
});

View File

@ -6,25 +6,25 @@ import { observer } from "mobx-react-lite";
import { IssueListHeader } from "components/issues/board-views/list/header";
import { IssueListBlock } from "components/issues/board-views/list/block";
// interfaces
import { IIssueState, IIssue } from "store/types/issue";
import { IIssueState, IIssue } from "types/issue";
// mobx hook
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
export const IssueListView = observer(() => {
const store: RootStore = useMobxStore();
const { issue: issueStore }: RootStore = useMobxStore();
console.log("issueStore", issueStore.states);
return (
<>
{store?.issue?.states &&
store?.issue?.states.length > 0 &&
store?.issue?.states.map((_state: IIssueState) => (
{issueStore?.states &&
issueStore?.states.length > 0 &&
issueStore?.states.map((_state: IIssueState) => (
<div key={_state.id} className="relative w-full">
<IssueListHeader state={_state} />
{store.issue.getFilteredIssuesByState(_state.id) &&
store.issue.getFilteredIssuesByState(_state.id).length > 0 ? (
{issueStore.getFilteredIssuesByState(_state.id) &&
issueStore.getFilteredIssuesByState(_state.id).length > 0 ? (
<div className="divide-y">
{store.issue.getFilteredIssuesByState(_state.id).map((_issue: IIssue) => (
{issueStore.getFilteredIssuesByState(_state.id).map((_issue: IIssue) => (
<IssueListBlock key={_issue.id} issue={_issue} />
))}
</div>

View File

@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
// mobx hook
import { useMobxStore } from "lib/mobx/store-provider";
// interfaces
import { IIssueLabel } from "store/types/issue";
import { IIssueLabel } from "types/issue";
export const RenderIssueLabel = observer(({ label }: { label: IIssueLabel }) => {
const store = useMobxStore();

View File

@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
// components
import { RenderIssueLabel } from "./filter-label-block";
// interfaces
import { IIssueLabel } from "store/types/issue";
import { IIssueLabel } from "types/issue";
// mobx hook
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";

View File

@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
// mobx hook
import { useMobxStore } from "lib/mobx/store-provider";
// interfaces
import { IIssuePriorityFilters } from "store/types/issue";
import { IIssuePriorityFilters } from "types/issue";
export const RenderIssuePriority = observer(({ priority }: { priority: IIssuePriorityFilters }) => {
const store = useMobxStore();

View File

@ -6,7 +6,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
// components
import { RenderIssuePriority } from "./filter-priority-block";
// interfaces
import { IIssuePriorityFilters } from "store/types/issue";
import { IIssuePriorityFilters } from "types/issue";
// constants
import { issuePriorityFilters } from "constants/data";

View File

@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
// mobx hook
import { useMobxStore } from "lib/mobx/store-provider";
// interfaces
import { IIssueState } from "store/types/issue";
import { IIssueState } from "types/issue";
// constants
import { issueGroupFilter } from "constants/data";

View File

@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
// components
import { RenderIssueState } from "./filter-state-block";
// interfaces
import { IIssueState } from "store/types/issue";
import { IIssueState } from "types/issue";
// mobx hook
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";

View File

@ -39,9 +39,11 @@ const IssueNavbar = observer(() => {
useEffect(() => {
if (workspace_slug && projectStore) {
if (board) {
console.log("setting");
projectStore.setActiveBoard(board.toString());
} else {
router.push(`/${workspace_slug}/${project_slug}?board=list`);
projectStore.setActiveBoard("list");
}
}
}, [board, router, projectStore, workspace_slug, project_slug]);

View File

@ -3,7 +3,7 @@ import { observer } from "mobx-react-lite";
// constants
import { issueViews } from "constants/data";
// interfaces
import { TIssueBoardKeys } from "store/types";
import { TIssueBoardKeys } from "types";
// mobx
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
@ -16,18 +16,18 @@ export const NavbarIssueBoardView = observer(() => {
const handleCurrentBoardView = (boardView: string) => {
projectStore.setActiveBoard(boardView);
router.replace(
router.push(
`/${workspace_slug}/${project_slug}?board=${boardView}${
issueStore?.userSelectedLabels && issueStore?.userSelectedLabels.length > 0
? `&labels=${issueStore?.userSelectedLabels.join(",")}`
issueStore?.filteredLabels && issueStore?.filteredLabels.length > 0
? `&labels=${issueStore?.filteredLabels.join(",")}`
: ""
}${
issueStore?.userSelectedPriorities && issueStore?.userSelectedPriorities.length > 0
? `&priorities=${issueStore?.userSelectedPriorities.join(",")}`
issueStore?.filteredPriorities && issueStore?.filteredPriorities.length > 0
? `&priorities=${issueStore?.filteredPriorities.join(",")}`
: ""
}${
issueStore?.userSelectedStates && issueStore?.userSelectedStates.length > 0
? `&states=${issueStore?.userSelectedStates.join(",")}`
issueStore?.filteredStates && issueStore?.filteredStates.length > 0
? `&states=${issueStore?.filteredStates.join(",")}`
: ""
}`
);
@ -37,8 +37,6 @@ export const NavbarIssueBoardView = observer(() => {
<>
{projectStore?.viewOptions &&
Object.keys(projectStore?.viewOptions).map((viewKey: string) => {
console.log("projectStore?.activeBoard", projectStore?.activeBoard);
console.log("viewKey", viewKey);
if (projectStore?.viewOptions[viewKey]) {
return (
<div

View File

@ -19,27 +19,25 @@ export const NavbarIssueFilter = observer(() => {
const pathName = router.asPath;
const handleOnSelect = (key: "states" | "labels" | "priorities", value: string) => {
if (key === "states") {
store.issue.userSelectedStates = store.issue.userSelectedStates.includes(value)
? store.issue.userSelectedStates.filter((s) => s !== value)
: [...store.issue.userSelectedStates, value];
} else if (key === "labels") {
store.issue.userSelectedLabels = store.issue.userSelectedLabels.includes(value)
? store.issue.userSelectedLabels.filter((l) => l !== value)
: [...store.issue.userSelectedLabels, value];
} else if (key === "priorities") {
store.issue.userSelectedPriorities = store.issue.userSelectedPriorities.includes(value)
? store.issue.userSelectedPriorities.filter((p) => p !== value)
: [...store.issue.userSelectedPriorities, value];
}
const paramsCommaSeparated = `${`board=${store.issue.currentIssueBoardView || "list"}`}${
store.issue.userSelectedPriorities.length > 0 ? `&priorities=${store.issue.userSelectedPriorities.join(",")}` : ""
}${store.issue.userSelectedStates.length > 0 ? `&states=${store.issue.userSelectedStates.join(",")}` : ""}${
store.issue.userSelectedLabels.length > 0 ? `&labels=${store.issue.userSelectedLabels.join(",")}` : ""
}`;
router.replace(`${pathName}?${paramsCommaSeparated}`);
// if (key === "states") {
// store.issue.userSelectedStates = store.issue.userSelectedStates.includes(value)
// ? store.issue.userSelectedStates.filter((s) => s !== value)
// : [...store.issue.userSelectedStates, value];
// } else if (key === "labels") {
// store.issue.userSelectedLabels = store.issue.userSelectedLabels.includes(value)
// ? store.issue.userSelectedLabels.filter((l) => l !== value)
// : [...store.issue.userSelectedLabels, value];
// } else if (key === "priorities") {
// store.issue.userSelectedPriorities = store.issue.userSelectedPriorities.includes(value)
// ? store.issue.userSelectedPriorities.filter((p) => p !== value)
// : [...store.issue.userSelectedPriorities, value];
// }
// const paramsCommaSeparated = `${`board=${store.issue.currentIssueBoardView || "list"}`}${
// store.issue.userSelectedPriorities.length > 0 ? `&priorities=${store.issue.userSelectedPriorities.join(",")}` : ""
// }${store.issue.userSelectedStates.length > 0 ? `&states=${store.issue.userSelectedStates.join(",")}` : ""}${
// store.issue.userSelectedLabels.length > 0 ? `&labels=${store.issue.userSelectedLabels.join(",")}` : ""
// }`;
// router.replace(`${pathName}?${paramsCommaSeparated}`);
};
return (
@ -69,7 +67,7 @@ export const NavbarIssueFilter = observer(() => {
</span>
),
onClick: () => handleOnSelect("priorities", priority),
isSelected: store.issue.userSelectedPriorities.includes(priority),
isSelected: store.issue.filteredPriorities.includes(priority),
})),
},
{
@ -85,7 +83,7 @@ export const NavbarIssueFilter = observer(() => {
</span>
),
onClick: () => handleOnSelect("states", state.id),
isSelected: store.issue.userSelectedStates.includes(state.id),
isSelected: store.issue.filteredStates.includes(state.id),
};
}),
},
@ -104,7 +102,7 @@ export const NavbarIssueFilter = observer(() => {
</span>
),
onClick: () => handleOnSelect("labels", label.id),
isSelected: store.issue.userSelectedLabels.includes(label.id),
isSelected: store.issue.filteredLabels.includes(label.id),
})),
},
]}

View File

@ -9,7 +9,7 @@ import useToast from "hooks/use-toast";
// ui
import { SecondaryButton } from "components/ui";
// types
import { Comment } from "store/types";
import { Comment } from "types";
// components
import Tiptap, { ITiptapRichTextEditor } from "components/tiptap";

View File

@ -16,7 +16,7 @@ import { ChatBubbleLeftEllipsisIcon, CheckIcon, XMarkIcon, EllipsisVerticalIcon
// helpers
import { timeAgo } from "helpers/date-time.helper";
// types
import { Comment } from "store/types";
import { Comment } from "types";
import Tiptap, { ITiptapRichTextEditor } from "components/tiptap";
const TiptapEditor = React.forwardRef<ITiptapRichTextEditor, ITiptapRichTextEditor>((props, ref) => (

View File

@ -1,7 +1,7 @@
// components
import { IssueReactions } from "components/issues/peek-overview";
// types
import { IIssue } from "store/types";
import { IIssue } from "types";
type Props = {
issue: IIssue;

View File

@ -10,7 +10,7 @@ import { Icon } from "components/ui";
import { copyTextToClipboard, addSpaceIfCamelCase } from "helpers/string.helper";
// types
import { IIssue } from "store/types";
import { IIssue } from "types";
// constants
import { issueGroupFilter, issuePriorityFilter } from "constants/data";

View File

@ -5,7 +5,7 @@ import { Dialog, Transition } from "@headlessui/react";
import { FullScreenPeekView, SidePeekView } from "components/issues/peek-overview";
// types
import type { IIssue } from "store/types";
import type { IIssue } from "types";
type Props = {
issue: IIssue | null;
@ -16,12 +16,7 @@ type Props = {
export type TPeekOverviewModes = "side" | "modal" | "full";
export const IssuePeekOverview: React.FC<Props> = ({
issue,
isOpen,
onClose,
workspaceSlug,
}) => {
export const IssuePeekOverview: React.FC<Props> = ({ issue, isOpen, onClose, workspaceSlug }) => {
const [peekOverviewMode, setPeekOverviewMode] = useState<TPeekOverviewModes>("side");
const handleClose = () => {

View File

@ -1,3 +1,4 @@
import { useEffect } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
// components
@ -10,15 +11,16 @@ import { IssuePeekOverview } from "components/issues/peek-overview";
// mobx store
import { RootStore } from "store/root";
import { useMobxStore } from "lib/mobx/store-provider";
import { useEffect } from "react";
export const ProjectDetailsView = () => {
export const ProjectDetailsView = observer(() => {
const router = useRouter();
const { workspace_slug, project_slug, states, labels, priorities } = router.query;
const { issue: issueStore }: RootStore = useMobxStore();
const { issue: issueStore, project: projectStore }: RootStore = useMobxStore();
const activeIssueId = issueStore.activePeekOverviewIssueId;
console.log("projectStore?.activeBoard", projectStore?.activeBoard);
const activeIssueId = issueStore.peekId;
useEffect(() => {
if (workspace_slug && project_slug) {
@ -33,14 +35,14 @@ export const ProjectDetailsView = () => {
return (
<div className="relative w-full h-full overflow-hidden">
{workspace_slug && (
{/* {workspace_slug && (
<IssuePeekOverview
isOpen={Boolean(activeIssueId)}
onClose={() => issueStore.setActivePeekOverviewIssueId(null)}
issue={issueStore?.issues?.find((_issue) => _issue.id === activeIssueId) || null}
workspaceSlug={workspace_slug.toString()}
/>
)}
)} */}
{issueStore?.loader && !issueStore.issues ? (
<div className="text-sm text-center py-10 text-custom-text-100">Loading...</div>
@ -51,23 +53,23 @@ export const ProjectDetailsView = () => {
Something went wrong.
</div>
) : (
issueStore?.currentIssueBoardView && (
projectStore?.activeBoard && (
<>
{issueStore?.currentIssueBoardView === "list" && (
{projectStore?.activeBoard === "list" && (
<div className="relative w-full h-full overflow-y-auto">
<div className="mx-auto px-4">
<IssueListView />
</div>
</div>
)}
{issueStore?.currentIssueBoardView === "kanban" && (
{projectStore?.activeBoard === "kanban" && (
<div className="relative w-full h-full mx-auto px-9 py-5">
<IssueKanbanView />
</div>
)}
{issueStore?.currentIssueBoardView === "calendar" && <IssueCalendarView />}
{issueStore?.currentIssueBoardView === "spreadsheet" && <IssueSpreadsheetView />}
{issueStore?.currentIssueBoardView === "gantt" && <IssueGanttView />}
{projectStore?.activeBoard === "calendar" && <IssueCalendarView />}
{projectStore?.activeBoard === "spreadsheet" && <IssueSpreadsheetView />}
{projectStore?.activeBoard === "gantt" && <IssueGanttView />}
</>
)
)}
@ -75,4 +77,4 @@ export const ProjectDetailsView = () => {
)}
</div>
);
};
});

View File

@ -7,7 +7,7 @@ import {
TIssueGroupKey,
IIssuePriorityFilters,
IIssueGroup,
} from "store/types/issue";
} from "types/issue";
// icons
import {
BacklogStateIcon,

View File

@ -3,7 +3,7 @@ import type { GetServerSideProps } from "next";
import { useRouter } from "next/router";
import Head from "next/head";
// types
import { TIssueBoardKeys } from "store/types";
import { TIssueBoardKeys } from "types";
import ProjectLayout from "layouts/project-layout";
import { ProjectDetailsView } from "components/views/project-details";

View File

@ -1,204 +1,79 @@
// mobx
import { observable, action, computed, makeObservable, runInAction, reaction } from "mobx";
// service
// services
import IssueService from "services/issue.service";
// store
import { RootStore } from "./root";
// types
import { IssueDetailType, TIssueBoardKeys } from "store/types/issue";
import { IIssue, IIssueState, IIssueLabel } from "./types";
// import { IssueDetailType, TIssueBoardKeys } from "types/issue";
import { IIssue, IIssueState, IIssueLabel } from "types/issue";
export interface IIssueStore {
currentIssueBoardView: TIssueBoardKeys | null;
loader: boolean;
error: any | null;
error: any;
// issue options
issues: IIssue[] | null;
states: IIssueState[] | null;
labels: IIssueLabel[] | null;
issues: IIssue[] | null;
issue_detail: IssueDetailType;
userSelectedStates: string[];
userSelectedLabels: string[];
userSelectedPriorities: string[];
activePeekOverviewIssueId: string | null;
getCountOfIssuesByState: (state: string) => number;
// filtering
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) => void;
getFilteredIssuesByState: (state: string) => IIssue[];
getUserSelectedFilter: (key: "state" | "priority" | "label", value: string) => boolean;
checkIfFilterExistsForKey: (key: "state" | "priority" | "label") => boolean;
clearUserSelectedFilter: (key: "state" | "priority" | "label" | "all") => void;
getIfFiltersIsEmpty: () => boolean;
getURLDefinition: (
workspaceSlug: string,
projectId: string,
action?: {
key: "state" | "priority" | "label" | "all";
value?: string;
removeAll?: boolean;
}
) => string;
setActivePeekOverviewIssueId: (value: any) => void;
setCurrentIssueBoardView: (view: TIssueBoardKeys) => void;
fetchPublicIssues: (workspaceSlug: string, projectId: string, params: any) => Promise<void>;
getIssueByIdAsync: (workspaceSlug: string, projectId: string, issueId: string) => Promise<IssueDetailType>;
}
class IssueStore {
currentIssueBoardView: TIssueBoardKeys | null = null;
class IssueStore implements IIssueStore {
loader: boolean = false;
error: any | null = null;
states: IIssueState[] | null = null;
labels: IIssueLabel[] | null = null;
issues: IIssue[] | null = null;
states: IIssueState[] | null = [];
labels: IIssueLabel[] | null = [];
issue_detail: IssueDetailType = {};
filteredStates: string[] = [];
filteredLabels: string[] = [];
filteredPriorities: string[] = [];
activePeekOverviewIssueId: string | null = null;
issues: IIssue[] | null = [];
issue_detail: any = {};
userSelectedStates: string[] = [];
userSelectedLabels: string[] = [];
userSelectedPriorities: string[] = [];
// root store
rootStore;
// service
issueService;
peekId: string | null = null;
rootStore: RootStore;
issueService: any;
constructor(_rootStore: any) {
makeObservable(this, {
// observable
currentIssueBoardView: observable,
loader: observable,
error: observable,
// issue options
states: observable.ref,
labels: observable.ref,
// filtering
filteredStates: observable.ref,
filteredLabels: observable.ref,
filteredPriorities: observable.ref,
// issues
issues: observable.ref,
issue_detail: observable.ref,
activePeekOverviewIssueId: observable.ref,
userSelectedStates: observable.ref,
userSelectedLabels: observable.ref,
userSelectedPriorities: observable.ref,
// action
setCurrentIssueBoardView: action,
// peek
peekId: observable.ref,
// actions
fetchPublicIssues: action,
// computed
setPeekId: action,
getFilteredIssuesByState: action,
});
this.rootStore = _rootStore;
this.issueService = new IssueService();
}
// computed
getCountOfIssuesByState(state_id: string): number {
return this.issues?.filter((issue) => issue.state == state_id).length || 0;
}
getFilteredIssuesByState(state_id: string): IIssue[] | [] {
return this.issues?.filter((issue) => issue.state == state_id) || [];
}
setActivePeekOverviewIssueId = (issueId: string | null) => (this.activePeekOverviewIssueId = issueId);
/**
*
* @param key Is the key of the filter, i.e. state, label, priority
* @param value Is the value of the filter, i.e. state_id, label_id, priority
* @returns boolean
*/
getUserSelectedFilter(key: "state" | "priority" | "label", value: string): boolean {
if (key == "state") {
return this.userSelectedStates.includes(value);
} else if (key == "label") {
return this.userSelectedLabels.includes(value);
} else if (key == "priority") {
return this.userSelectedPriorities.includes(value);
} else {
return false;
}
}
checkIfFilterExistsForKey: (key: "state" | "priority" | "label") => boolean = (key) => {
if (key == "state") {
return this.userSelectedStates.length > 0;
} else if (key == "label") {
return this.userSelectedLabels.length > 0;
} else if (key == "priority") {
return this.userSelectedPriorities.length > 0;
} else {
return false;
}
};
clearUserSelectedFilter(key: "state" | "priority" | "label" | "all") {
if (key == "state") {
this.userSelectedStates = [];
} else if (key == "label") {
this.userSelectedLabels = [];
} else if (key == "priority") {
this.userSelectedPriorities = [];
} else if (key == "all") {
this.userSelectedStates = [];
this.userSelectedLabels = [];
this.userSelectedPriorities = [];
}
}
getIfFiltersIsEmpty: () => boolean = () =>
this.userSelectedStates.length === 0 &&
this.userSelectedLabels.length === 0 &&
this.userSelectedPriorities.length === 0;
getURLDefinition = (
workspaceSlug: string,
projectId: string,
action?: {
key: "state" | "priority" | "label" | "all";
value?: string;
removeAll?: boolean;
}
) => {
let url = `/${workspaceSlug}/${projectId}?board=${this.currentIssueBoardView}`;
if (action) {
if (action.key === "state")
this.userSelectedStates = action.removeAll
? []
: [...this.userSelectedStates].filter((state) => state !== action.value);
if (action.key === "label")
this.userSelectedLabels = action.removeAll
? []
: [...this.userSelectedLabels].filter((label) => label !== action.value);
if (action.key === "priority")
this.userSelectedPriorities = action.removeAll
? []
: [...this.userSelectedPriorities].filter((priority) => priority !== action.value);
if (action.key === "all") {
this.userSelectedStates = [];
this.userSelectedLabels = [];
this.userSelectedPriorities = [];
}
}
if (this.checkIfFilterExistsForKey("state")) {
url += `&states=${this.userSelectedStates.join(",")}`;
}
if (this.checkIfFilterExistsForKey("label")) {
url += `&labels=${this.userSelectedLabels.join(",")}`;
}
if (this.checkIfFilterExistsForKey("priority")) {
url += `&priorities=${this.userSelectedPriorities.join(",")}`;
}
return url;
};
// action
setCurrentIssueBoardView = async (view: TIssueBoardKeys) => {
this.currentIssueBoardView = view;
};
fetchPublicIssues = async (workspaceSlug: string, projectId: string, params: any) => {
try {
this.loader = true;
@ -216,352 +91,19 @@ class IssueStore {
this.issues = _issues;
this.loader = false;
});
return response;
}
} catch (error) {
this.loader = false;
this.error = error;
return error;
}
};
getIssueByIdAsync = async (workspaceSlug: string, projectId: string, issueId: string): Promise<IssueDetailType> => {
try {
const response = this.issues?.find((issue) => issue.id === issueId);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
issue: response,
comments: [],
reactions: [],
votes: [],
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
this.getIssueReactionsAsync(workspaceSlug, projectId, issueId);
this.getIssueVotesAsync(workspaceSlug, projectId, issueId);
this.getIssueCommentsAsync(workspaceSlug, projectId, issueId);
}
return this.issue_detail[issueId] as any;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
setPeekId = (issueId: string) => {
this.peekId = issueId;
};
getIssueVotesAsync = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
const response = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
votes: response,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
createIssueVoteAsync = async (
workspaceSlug: string,
projectId: string,
issueId: string,
data: {
vote: 1 | -1;
}
) => {
try {
const response = await this.issueService.createIssueVote(workspaceSlug, projectId, issueId, data);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
votes: [
...{ ...this.issue_detail }[issueId].votes.filter(
(vote) => vote.actor !== this.rootStore?.user?.currentUser?.id
),
response,
],
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
deleteIssueVoteAsync = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
const _votes = (this.issue_detail[issueId].votes = this.issue_detail[issueId].votes.filter(
(vote) => vote.actor !== this.rootStore?.user?.user?.id
));
runInAction(() => {
this.issue_detail[issueId].votes = _votes;
});
const response = await this.issueService.deleteIssueVote(workspaceSlug, projectId, issueId);
const votesAfterCall = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId);
if (votesAfterCall)
runInAction(() => {
this.issue_detail[issueId].votes = votesAfterCall;
});
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
getIssueReactionsAsync = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
const response = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
reactions: response,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
createIssueReactionAsync = async (workspaceSlug: string, projectId: string, issueId: string, data: any) => {
try {
const response = await this.issueService.createIssueReaction(workspaceSlug, projectId, issueId, data);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
reactions: [...this.issue_detail[issueId].reactions, response],
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
deleteIssueReactionAsync = async (workspaceSlug: string, projectId: string, issueId: string, reactionHex: string) => {
try {
const newReactionsList = this.issue_detail[issueId].reactions.filter(
(reaction) => reaction.reaction !== reactionHex
);
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
reactions: newReactionsList,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
const response = await this.issueService.deleteIssueReaction(workspaceSlug, projectId, issueId, reactionHex);
const reactionsAfterCall = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId);
if (reactionsAfterCall) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
reactions: reactionsAfterCall,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
getIssueCommentsAsync = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
const response = await this.issueService.getIssueComments(workspaceSlug, projectId, issueId);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
comments: response,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
createIssueCommentAsync = async (workspaceSlug: string, projectId: string, issueId: string, data: any) => {
try {
const response = await this.issueService.createIssueComment(workspaceSlug, projectId, issueId, data);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
comments: [...this.issue_detail[issueId].comments, response],
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
updateIssueCommentAsync = async (
workspaceSlug: string,
projectId: string,
issueId: string,
commentId: string,
data: any
) => {
try {
const response = await this.issueService.updateIssueComment(workspaceSlug, projectId, issueId, commentId, data);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
comments: [
...this.issue_detail[issueId].comments.filter((comment) => comment.id !== response.id),
response,
],
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
deleteIssueCommentAsync = async (workspaceSlug: string, projectId: string, issueId: string, commentId: string) => {
try {
const newCommentsList = this.issue_detail[issueId].comments.filter((comment) => comment.id !== commentId);
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
comments: newCommentsList,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
const response = await this.issueService.deleteIssueComment(workspaceSlug, projectId, issueId, commentId);
const commentsAfterCall = await this.issueService.getIssueComments(workspaceSlug, projectId, issueId);
if (commentsAfterCall) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
comments: commentsAfterCall,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
getFilteredIssuesByState = (state_id: string): IIssue[] | [] =>
this.issues?.filter((issue) => issue.state == state_id) || [];
}
export default IssueStore;

View File

@ -0,0 +1,567 @@
// mobx
import { observable, action, computed, makeObservable, runInAction, reaction } from "mobx";
// service
import IssueService from "services/issue.service";
// types
import { IssueDetailType, TIssueBoardKeys } from "types/issue";
import { IIssue, IIssueState, IIssueLabel } from "../types";
export interface IIssueStore {
currentIssueBoardView: TIssueBoardKeys | null;
loader: boolean;
error: any | null;
states: IIssueState[] | null;
labels: IIssueLabel[] | null;
issues: IIssue[] | null;
issue_detail: IssueDetailType;
userSelectedStates: string[];
userSelectedLabels: string[];
userSelectedPriorities: string[];
activePeekOverviewIssueId: string | null;
getCountOfIssuesByState: (state: string) => number;
getFilteredIssuesByState: (state: string) => IIssue[];
getUserSelectedFilter: (key: "state" | "priority" | "label", value: string) => boolean;
checkIfFilterExistsForKey: (key: "state" | "priority" | "label") => boolean;
clearUserSelectedFilter: (key: "state" | "priority" | "label" | "all") => void;
getIfFiltersIsEmpty: () => boolean;
getURLDefinition: (
workspaceSlug: string,
projectId: string,
action?: {
key: "state" | "priority" | "label" | "all";
value?: string;
removeAll?: boolean;
}
) => string;
setActivePeekOverviewIssueId: (value: any) => void;
setCurrentIssueBoardView: (view: TIssueBoardKeys) => void;
fetchPublicIssues: (workspaceSlug: string, projectId: string, params: any) => Promise<void>;
getIssueByIdAsync: (workspaceSlug: string, projectId: string, issueId: string) => Promise<IssueDetailType>;
}
class IssueLegacyStore {
currentIssueBoardView: TIssueBoardKeys | null = null;
loader: boolean = false;
error: any | null = null;
states: IIssueState[] | null = null;
labels: IIssueLabel[] | null = null;
issues: IIssue[] | null = null;
issue_detail: IssueDetailType = {};
activePeekOverviewIssueId: string | null = null;
userSelectedStates: string[] = [];
userSelectedLabels: string[] = [];
userSelectedPriorities: string[] = [];
// root store
rootStore;
// service
issueService;
constructor(_rootStore: any) {
makeObservable(this, {
// observable
currentIssueBoardView: observable,
loader: observable,
error: observable,
states: observable.ref,
labels: observable.ref,
issues: observable.ref,
issue_detail: observable.ref,
activePeekOverviewIssueId: observable.ref,
userSelectedStates: observable.ref,
userSelectedLabels: observable.ref,
userSelectedPriorities: observable.ref,
// action
setCurrentIssueBoardView: action,
fetchPublicIssues: action,
// computed
});
this.rootStore = _rootStore;
this.issueService = new IssueService();
}
// computed
getCountOfIssuesByState(state_id: string): number {
return this.issues?.filter((issue) => issue.state == state_id).length || 0;
}
getFilteredIssuesByState(state_id: string): IIssue[] | [] {
return this.issues?.filter((issue) => issue.state == state_id) || [];
}
setActivePeekOverviewIssueId = (issueId: string | null) => (this.activePeekOverviewIssueId = issueId);
/**
*
* @param key Is the key of the filter, i.e. state, label, priority
* @param value Is the value of the filter, i.e. state_id, label_id, priority
* @returns boolean
*/
getUserSelectedFilter(key: "state" | "priority" | "label", value: string): boolean {
if (key == "state") {
return this.userSelectedStates.includes(value);
} else if (key == "label") {
return this.userSelectedLabels.includes(value);
} else if (key == "priority") {
return this.userSelectedPriorities.includes(value);
} else {
return false;
}
}
checkIfFilterExistsForKey: (key: "state" | "priority" | "label") => boolean = (key) => {
if (key == "state") {
return this.userSelectedStates.length > 0;
} else if (key == "label") {
return this.userSelectedLabels.length > 0;
} else if (key == "priority") {
return this.userSelectedPriorities.length > 0;
} else {
return false;
}
};
clearUserSelectedFilter(key: "state" | "priority" | "label" | "all") {
if (key == "state") {
this.userSelectedStates = [];
} else if (key == "label") {
this.userSelectedLabels = [];
} else if (key == "priority") {
this.userSelectedPriorities = [];
} else if (key == "all") {
this.userSelectedStates = [];
this.userSelectedLabels = [];
this.userSelectedPriorities = [];
}
}
getIfFiltersIsEmpty: () => boolean = () =>
this.userSelectedStates.length === 0 &&
this.userSelectedLabels.length === 0 &&
this.userSelectedPriorities.length === 0;
getURLDefinition = (
workspaceSlug: string,
projectId: string,
action?: {
key: "state" | "priority" | "label" | "all";
value?: string;
removeAll?: boolean;
}
) => {
let url = `/${workspaceSlug}/${projectId}?board=${this.currentIssueBoardView}`;
if (action) {
if (action.key === "state")
this.userSelectedStates = action.removeAll
? []
: [...this.userSelectedStates].filter((state) => state !== action.value);
if (action.key === "label")
this.userSelectedLabels = action.removeAll
? []
: [...this.userSelectedLabels].filter((label) => label !== action.value);
if (action.key === "priority")
this.userSelectedPriorities = action.removeAll
? []
: [...this.userSelectedPriorities].filter((priority) => priority !== action.value);
if (action.key === "all") {
this.userSelectedStates = [];
this.userSelectedLabels = [];
this.userSelectedPriorities = [];
}
}
if (this.checkIfFilterExistsForKey("state")) {
url += `&states=${this.userSelectedStates.join(",")}`;
}
if (this.checkIfFilterExistsForKey("label")) {
url += `&labels=${this.userSelectedLabels.join(",")}`;
}
if (this.checkIfFilterExistsForKey("priority")) {
url += `&priorities=${this.userSelectedPriorities.join(",")}`;
}
return url;
};
// action
setCurrentIssueBoardView = async (view: TIssueBoardKeys) => {
this.currentIssueBoardView = view;
};
fetchPublicIssues = async (workspaceSlug: string, projectId: string, params: any) => {
try {
this.loader = true;
this.error = null;
const response = await this.issueService.getPublicIssues(workspaceSlug, projectId, params);
if (response) {
const _states: IIssueState[] = [...response?.states];
const _labels: IIssueLabel[] = [...response?.labels];
const _issues: IIssue[] = [...response?.issues];
runInAction(() => {
this.states = _states;
this.labels = _labels;
this.issues = _issues;
this.loader = false;
});
return response;
}
} catch (error) {
this.loader = false;
this.error = error;
return error;
}
};
getIssueByIdAsync = async (workspaceSlug: string, projectId: string, issueId: string): Promise<IssueDetailType> => {
try {
const response = this.issues?.find((issue) => issue.id === issueId);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
issue: response,
comments: [],
reactions: [],
votes: [],
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
this.getIssueReactionsAsync(workspaceSlug, projectId, issueId);
this.getIssueVotesAsync(workspaceSlug, projectId, issueId);
this.getIssueCommentsAsync(workspaceSlug, projectId, issueId);
}
return this.issue_detail[issueId] as any;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
getIssueVotesAsync = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
const response = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
votes: response,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
createIssueVoteAsync = async (
workspaceSlug: string,
projectId: string,
issueId: string,
data: {
vote: 1 | -1;
}
) => {
try {
const response = await this.issueService.createIssueVote(workspaceSlug, projectId, issueId, data);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
votes: [
...{ ...this.issue_detail }[issueId].votes.filter(
(vote) => vote.actor !== this.rootStore?.user?.currentUser?.id
),
response,
],
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
deleteIssueVoteAsync = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
const _votes = (this.issue_detail[issueId].votes = this.issue_detail[issueId].votes.filter(
(vote) => vote.actor !== this.rootStore?.user?.user?.id
));
runInAction(() => {
this.issue_detail[issueId].votes = _votes;
});
const response = await this.issueService.deleteIssueVote(workspaceSlug, projectId, issueId);
const votesAfterCall = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId);
if (votesAfterCall)
runInAction(() => {
this.issue_detail[issueId].votes = votesAfterCall;
});
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
getIssueReactionsAsync = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
const response = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
reactions: response,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
createIssueReactionAsync = async (workspaceSlug: string, projectId: string, issueId: string, data: any) => {
try {
const response = await this.issueService.createIssueReaction(workspaceSlug, projectId, issueId, data);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
reactions: [...this.issue_detail[issueId].reactions, response],
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
deleteIssueReactionAsync = async (workspaceSlug: string, projectId: string, issueId: string, reactionHex: string) => {
try {
const newReactionsList = this.issue_detail[issueId].reactions.filter(
(reaction) => reaction.reaction !== reactionHex
);
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
reactions: newReactionsList,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
const response = await this.issueService.deleteIssueReaction(workspaceSlug, projectId, issueId, reactionHex);
const reactionsAfterCall = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId);
if (reactionsAfterCall) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
reactions: reactionsAfterCall,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
getIssueCommentsAsync = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
const response = await this.issueService.getIssueComments(workspaceSlug, projectId, issueId);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
comments: response,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
createIssueCommentAsync = async (workspaceSlug: string, projectId: string, issueId: string, data: any) => {
try {
const response = await this.issueService.createIssueComment(workspaceSlug, projectId, issueId, data);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
comments: [...this.issue_detail[issueId].comments, response],
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
updateIssueCommentAsync = async (
workspaceSlug: string,
projectId: string,
issueId: string,
commentId: string,
data: any
) => {
try {
const response = await this.issueService.updateIssueComment(workspaceSlug, projectId, issueId, commentId, data);
if (response) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
comments: [
...this.issue_detail[issueId].comments.filter((comment) => comment.id !== response.id),
response,
],
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
deleteIssueCommentAsync = async (workspaceSlug: string, projectId: string, issueId: string, commentId: string) => {
try {
const newCommentsList = this.issue_detail[issueId].comments.filter((comment) => comment.id !== commentId);
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
comments: newCommentsList,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
const response = await this.issueService.deleteIssueComment(workspaceSlug, projectId, issueId, commentId);
const commentsAfterCall = await this.issueService.getIssueComments(workspaceSlug, projectId, issueId);
if (commentsAfterCall) {
const _issue_detail = {
...this.issue_detail,
[issueId]: {
...this.issue_detail[issueId],
comments: commentsAfterCall,
},
};
runInAction(() => {
this.issue_detail = _issue_detail;
});
}
return response;
} catch (error) {
this.loader = false;
this.error = error;
throw error;
}
};
}
export default IssueLegacyStore;

View File

@ -3,7 +3,7 @@ import { observable, action, makeObservable, runInAction } from "mobx";
// service
import ProjectService from "services/project.service";
// types
import { IWorkspace, IProject, IProjectSettings } from "./types";
import { IWorkspace, IProject, IProjectSettings } from "../types";
export interface IProjectStore {
loader: boolean;

View File

@ -6,7 +6,7 @@ import ThemeStore from "./theme";
import IssueStore, { IIssueStore } from "./issue";
import ProjectStore, { IProjectStore } from "./project";
// types
import { IThemeStore } from "./types";
import { IThemeStore } from "../types";
enableStaticRendering(typeof window === "undefined");

View File

@ -1,7 +1,7 @@
// mobx
import { observable, action, computed, makeObservable, runInAction } from "mobx";
// types
import { IThemeStore } from "./types";
import { IThemeStore } from "../types";
class ThemeStore implements IThemeStore {
theme: "light" | "dark" = "light";

View File

@ -3,7 +3,7 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx"
// service
import UserService from "services/user.service";
// types
import { IUserStore } from "./types";
import { IUserStore } from "../types";
class UserStore implements IUserStore {
currentUser: any | null = null;