From 41e29e936e8787d98b5c1d3b6c547deff16c3888 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Tue, 4 Jun 2024 19:07:35 +0530 Subject: [PATCH] chore: update filtering logic --- space/app/page/page.tsx | 27 ++++++ .../issues/filters/applied-filters/root.tsx | 18 ++-- space/components/issues/filters/root.tsx | 21 ++-- space/components/issues/navbar/controls.tsx | 21 ++-- .../issues/navbar/issue-board-view.tsx | 15 ++- .../peek-overview/full-screen-peek-view.tsx | 2 +- .../issues/peek-overview/issue-activity.tsx | 10 +- .../issues/peek-overview/issue-details.tsx | 47 +++++---- .../peek-overview/issue-emoji-reactions.tsx | 17 ++-- .../issues/peek-overview/issue-reaction.tsx | 32 +++---- .../peek-overview/issue-vote-reactions.tsx | 23 +++-- .../issues/peek-overview/side-peek-view.tsx | 2 +- space/components/views/project-details.tsx | 3 +- space/hooks/store/use-project.ts | 11 --- space/services/file.service.ts | 58 ----------- space/store/issue-filters.store.ts | 77 +++++++-------- space/store/project.store.ts | 96 ------------------- space/store/publish/publish.store.ts | 30 ++++++ 18 files changed, 196 insertions(+), 314 deletions(-) delete mode 100644 space/hooks/store/use-project.ts delete mode 100644 space/store/project.store.ts diff --git a/space/app/page/page.tsx b/space/app/page/page.tsx index e69de29bb..43e7a0051 100644 --- a/space/app/page/page.tsx +++ b/space/app/page/page.tsx @@ -0,0 +1,27 @@ +"use client"; + +import useSWR from "swr"; +// hooks +import { usePublish, usePublishList } from "@/hooks/store"; + +type Props = { + params: { + anchor: string; + }; +}; + +const PageDetailsPage = (props: Props) => { + const { params } = props; + const { anchor } = params; + // store hooks + const { fetchPublishSettings } = usePublishList(); + const publishSettings = usePublish(anchor); + + useSWR(anchor ? `PUBLISH_SETTINGS_${anchor}` : null, anchor ? () => fetchPublishSettings(anchor) : null); + + if (!publishSettings) return null; + + return <>Page details; +}; + +export default PageDetailsPage; diff --git a/space/components/issues/filters/applied-filters/root.tsx b/space/components/issues/filters/applied-filters/root.tsx index d9bba46a7..5d6a404ed 100644 --- a/space/components/issues/filters/applied-filters/root.tsx +++ b/space/components/issues/filters/applied-filters/root.tsx @@ -5,7 +5,7 @@ import cloneDeep from "lodash/cloneDeep"; import { observer } from "mobx-react-lite"; import { useRouter } from "next/navigation"; // hooks -import { useIssue, useIssueFilter, usePublish } from "@/hooks/store"; +import { useIssue, useIssueFilter } from "@/hooks/store"; // store import { TIssueQueryFilters } from "@/types/issue"; // components @@ -20,10 +20,10 @@ export const IssueAppliedFilters: FC = observer((props) => // router const router = useRouter(); // store hooks - const { issueFilters, initIssueFilters, updateIssueFilters } = useIssueFilter(); + const { getIssueFilters, initIssueFilters, updateIssueFilters } = useIssueFilter(); const { states, labels } = useIssue(); - const { project: projectID } = usePublish(anchor); - + // derived values + const issueFilters = getIssueFilters(anchor); const activeLayout = issueFilters?.display_filters?.layout || undefined; const userFilters = issueFilters?.filters || {}; @@ -53,23 +53,19 @@ export const IssueAppliedFilters: FC = observer((props) => const handleFilters = useCallback( (key: keyof TIssueQueryFilters, value: string | null) => { - if (!projectID) return; - let newValues = cloneDeep(issueFilters?.filters?.[key]) ?? []; if (value === null) newValues = []; else if (newValues.includes(value)) newValues.splice(newValues.indexOf(value), 1); - updateIssueFilters(projectID, "filters", key, newValues); + updateIssueFilters(anchor, "filters", key, newValues); updateRouteParams(key, newValues); }, - [projectID, issueFilters, updateIssueFilters, updateRouteParams] + [anchor, issueFilters, updateIssueFilters, updateRouteParams] ); const handleRemoveAllFilters = () => { - if (!projectID) return; - - initIssueFilters(projectID, { + initIssueFilters(anchor, { display_filters: { layout: activeLayout || "list" }, filters: { state: [], diff --git a/space/components/issues/filters/root.tsx b/space/components/issues/filters/root.tsx index de972ea8a..dba13f9fb 100644 --- a/space/components/issues/filters/root.tsx +++ b/space/components/issues/filters/root.tsx @@ -17,17 +17,18 @@ import { useIssue, useIssueFilter } from "@/hooks/store"; import { TIssueQueryFilters } from "@/types/issue"; type IssueFiltersDropdownProps = { - workspaceSlug: string; - projectId: string; + anchor: string; }; export const IssueFiltersDropdown: FC = observer((props) => { + const { anchor } = props; + // router const router = useRouter(); - const { workspaceSlug, projectId } = props; // hooks - const { issueFilters, updateIssueFilters } = useIssueFilter(); + const { getIssueFilters, updateIssueFilters } = useIssueFilter(); const { states, labels } = useIssue(); - + // derived values + const issueFilters = getIssueFilters(anchor); const activeLayout = issueFilters?.display_filters?.layout || undefined; const updateRouteParams = useCallback( @@ -37,24 +38,24 @@ export const IssueFiltersDropdown: FC = observer((pro const labels = key === "labels" ? value : issueFilters?.filters?.labels ?? []; const { queryParam } = queryParamGenerator({ board: activeLayout, priority, state, labels }); - router.push(`/${workspaceSlug}/${projectId}?${queryParam}`); + router.push(`/issues/${anchor}?${queryParam}`); }, - [workspaceSlug, projectId, activeLayout, issueFilters, router] + [anchor, activeLayout, issueFilters, router] ); const handleFilters = useCallback( (key: keyof TIssueQueryFilters, value: string) => { - if (!projectId || !value) return; + if (!value) return; const newValues = cloneDeep(issueFilters?.filters?.[key]) ?? []; if (newValues.includes(value)) newValues.splice(newValues.indexOf(value), 1); else newValues.push(value); - updateIssueFilters(projectId, "filters", key, newValues); + updateIssueFilters(anchor, "filters", key, newValues); updateRouteParams(key, newValues); }, - [projectId, issueFilters, updateIssueFilters, updateRouteParams] + [anchor, issueFilters, updateIssueFilters, updateRouteParams] ); return ( diff --git a/space/components/issues/navbar/controls.tsx b/space/components/issues/navbar/controls.tsx index b6302e2fc..6bdaf655e 100644 --- a/space/components/issues/navbar/controls.tsx +++ b/space/components/issues/navbar/controls.tsx @@ -35,16 +35,17 @@ export const NavbarControls: FC = observer((props) => { const priority = searchParams.get("priority") || undefined; const peekId = searchParams.get("peekId") || undefined; // hooks - const { issueFilters, isIssueFiltersUpdated, initIssueFilters } = useIssueFilter(); + const { getIssueFilters, isIssueFiltersUpdated, initIssueFilters } = useIssueFilter(); const { setPeekId } = useIssueDetails(); // derived values + const { anchor, views, workspace_detail } = publishSettings; + const issueFilters = anchor ? getIssueFilters(anchor) : undefined; const activeLayout = issueFilters?.display_filters?.layout || undefined; - const { project, views, workspace_detail } = publishSettings; const isInIframe = useIsInIframe(); useEffect(() => { - if (project && workspace_detail) { + if (anchor && workspace_detail) { const viewsAcceptable: string[] = []; let currentBoard: TIssueLayout | null = null; @@ -75,14 +76,15 @@ export const NavbarControls: FC = observer((props) => { }, }; - if (!isIssueFiltersUpdated(params)) { - initIssueFilters(project, params); - router.push(`/${workspace_detail.slug}/${project}?${queryParam}`); + if (!isIssueFiltersUpdated(anchor, params)) { + initIssueFilters(anchor, params); + router.push(`/issues/${anchor}?${queryParam}`); } } } } }, [ + anchor, board, labels, state, @@ -94,22 +96,21 @@ export const NavbarControls: FC = observer((props) => { setPeekId, isIssueFiltersUpdated, views, - project, workspace_detail, ]); - if (!workspace_detail || !project) return; + if (!anchor) return null; return ( <> {/* issue views */}
- +
{/* issue filters */}
- +
{/* theming */} diff --git a/space/components/issues/navbar/issue-board-view.tsx b/space/components/issues/navbar/issue-board-view.tsx index 711229961..2bb8b671c 100644 --- a/space/components/issues/navbar/issue-board-view.tsx +++ b/space/components/issues/navbar/issue-board-view.tsx @@ -13,11 +13,12 @@ import { useIssueFilter } from "@/hooks/store"; import { TIssueLayout } from "@/types/issue"; type NavbarIssueBoardViewProps = { - workspaceSlug: string; - projectId: string; + anchor: string; }; export const NavbarIssueBoardView: FC = observer((props) => { + const { anchor } = props; + // router const router = useRouter(); const searchParams = useSearchParams(); // query params @@ -25,18 +26,16 @@ export const NavbarIssueBoardView: FC = observer((pro const state = searchParams.get("state") || undefined; const priority = searchParams.get("priority") || undefined; const peekId = searchParams.get("peekId") || undefined; - // props - const { workspaceSlug, projectId } = props; // hooks - const { layoutOptions, issueFilters, updateIssueFilters } = useIssueFilter(); - + const { layoutOptions, getIssueFilters, updateIssueFilters } = useIssueFilter(); // derived values + const issueFilters = getIssueFilters(anchor); const activeLayout = issueFilters?.display_filters?.layout || undefined; const handleCurrentBoardView = (boardView: TIssueLayout) => { - updateIssueFilters(projectId, "display_filters", "layout", boardView); + updateIssueFilters(anchor, "display_filters", "layout", boardView); const { queryParam } = queryParamGenerator({ board: boardView, peekId, priority, state, labels }); - router.push(`/${workspaceSlug}/${projectId}?${queryParam}`); + router.push(`/issues/${anchor}?${queryParam}`); }; return ( diff --git a/space/components/issues/peek-overview/full-screen-peek-view.tsx b/space/components/issues/peek-overview/full-screen-peek-view.tsx index 831b473d1..4e9d5ed8c 100644 --- a/space/components/issues/peek-overview/full-screen-peek-view.tsx +++ b/space/components/issues/peek-overview/full-screen-peek-view.tsx @@ -29,7 +29,7 @@ export const FullScreenPeekView: React.FC = observer((props) => {
{/* issue title and description */}
- +
{/* divider */}
diff --git a/space/components/issues/peek-overview/issue-activity.tsx b/space/components/issues/peek-overview/issue-activity.tsx index fbce367b0..1ccb7fa88 100644 --- a/space/components/issues/peek-overview/issue-activity.tsx +++ b/space/components/issues/peek-overview/issue-activity.tsx @@ -7,7 +7,7 @@ import { Button } from "@plane/ui"; import { CommentCard, AddComment } from "@/components/issues/peek-overview"; import { Icon } from "@/components/ui"; // hooks -import { useIssueDetails, useProject, useUser } from "@/hooks/store"; +import { useIssueDetails, usePublish, useUser } from "@/hooks/store"; import useIsInIframe from "@/hooks/use-is-in-iframe"; // types import { IIssue } from "@/types/issue"; @@ -21,13 +21,13 @@ export const PeekOverviewIssueActivity: React.FC = observer((props) => { const { anchor } = props; // router const pathname = usePathname(); - // store - const { canComment } = useProject(); + // store hooks const { details, peekId } = useIssueDetails(); const { data: currentUser } = useUser(); - const isInIframe = useIsInIframe(); - + const { canComment } = usePublish(anchor); + // derived values const comments = details[peekId || ""]?.comments || []; + const isInIframe = useIsInIframe(); return (
diff --git a/space/components/issues/peek-overview/issue-details.tsx b/space/components/issues/peek-overview/issue-details.tsx index 5fe73f67a..4dc8d84a6 100644 --- a/space/components/issues/peek-overview/issue-details.tsx +++ b/space/components/issues/peek-overview/issue-details.tsx @@ -5,26 +5,33 @@ import { IssueReactions } from "@/components/issues/peek-overview"; import { IIssue } from "@/types/issue"; type Props = { + anchor: string; issueDetails: IIssue; }; -export const PeekOverviewIssueDetails: React.FC = ({ issueDetails }) => ( -
-
- {issueDetails.project_detail.identifier}-{issueDetails.sequence_id} -
-

{issueDetails.name}

- {issueDetails.description_html !== "" && issueDetails.description_html !== "

" && ( -

" - : issueDetails.description_html - } - /> - )} - -
-); +export const PeekOverviewIssueDetails: React.FC = (props) => { + const { anchor, issueDetails } = props; + + const description = issueDetails.description_html; + + return ( +
+
+ {issueDetails.project_detail.identifier}-{issueDetails.sequence_id} +
+

{issueDetails.name}

+ {description !== "" && description !== "

" && ( +

" + : description + } + /> + )} + +
+ ); +}; diff --git a/space/components/issues/peek-overview/issue-emoji-reactions.tsx b/space/components/issues/peek-overview/issue-emoji-reactions.tsx index 5de3beb25..ae960eab3 100644 --- a/space/components/issues/peek-overview/issue-emoji-reactions.tsx +++ b/space/components/issues/peek-overview/issue-emoji-reactions.tsx @@ -10,11 +10,12 @@ import { queryParamGenerator } from "@/helpers/query-param-generator"; import { useIssueDetails, useUser } from "@/hooks/store"; type IssueEmojiReactionsProps = { - workspaceSlug: string; - projectId: string; + anchor: string; }; export const IssueEmojiReactions: React.FC = observer((props) => { + const { anchor } = props; + // router const router = useRouter(); const pathName = usePathname(); const searchParams = useSearchParams(); @@ -24,9 +25,7 @@ export const IssueEmojiReactions: React.FC = observer( const state = searchParams.get("state") || undefined; const priority = searchParams.get("priority") || undefined; const labels = searchParams.get("labels") || undefined; - - const { workspaceSlug, projectId } = props; - // store + // store hooks const issueDetailsStore = useIssueDetails(); const { data: user } = useUser(); @@ -37,13 +36,13 @@ export const IssueEmojiReactions: React.FC = observer( const userReactions = reactions?.filter((r) => r.actor_detail.id === user?.id); const handleAddReaction = (reactionHex: string) => { - if (!workspaceSlug || !projectId || !issueId) return; - issueDetailsStore.addIssueReaction(workspaceSlug.toString(), projectId.toString(), issueId, reactionHex); + if (!issueId) return; + issueDetailsStore.addIssueReaction(anchor, issueId, reactionHex); }; const handleRemoveReaction = (reactionHex: string) => { - if (!workspaceSlug || !projectId || !issueId) return; - issueDetailsStore.removeIssueReaction(workspaceSlug.toString(), projectId.toString(), issueId, reactionHex); + if (!issueId) return; + issueDetailsStore.removeIssueReaction(anchor, issueId, reactionHex); }; const handleReactionClick = (reactionHex: string) => { diff --git a/space/components/issues/peek-overview/issue-reaction.tsx b/space/components/issues/peek-overview/issue-reaction.tsx index 58266f314..c3b580abc 100644 --- a/space/components/issues/peek-overview/issue-reaction.tsx +++ b/space/components/issues/peek-overview/issue-reaction.tsx @@ -1,33 +1,31 @@ -import { useParams } from "next/navigation"; +import { observer } from "mobx-react-lite"; import { IssueEmojiReactions, IssueVotes } from "@/components/issues/peek-overview"; -import { useProject } from "@/hooks/store"; +// hooks +import { usePublish } from "@/hooks/store"; import useIsInIframe from "@/hooks/use-is-in-iframe"; -// type IssueReactionsProps = { -// workspaceSlug: string; -// projectId: string; -// }; +type Props = { + anchor: string; +}; -export const IssueReactions: React.FC = () => { - const { workspaceSlug, projectId } = useParams(); - - const { canVote, canReact } = useProject(); +export const IssueReactions: React.FC = observer((props) => { + const { anchor } = props; + // store hooks + const { canVote, canReact } = usePublish(anchor); const isInIframe = useIsInIframe(); return (
{canVote && ( - <> -
- -
- +
+ +
)} {!isInIframe && canReact && (
- +
)}
); -}; +}); diff --git a/space/components/issues/peek-overview/issue-vote-reactions.tsx b/space/components/issues/peek-overview/issue-vote-reactions.tsx index 14e9ef30e..6b24e5a9f 100644 --- a/space/components/issues/peek-overview/issue-vote-reactions.tsx +++ b/space/components/issues/peek-overview/issue-vote-reactions.tsx @@ -12,11 +12,14 @@ import { useIssueDetails, useUser } from "@/hooks/store"; import useIsInIframe from "@/hooks/use-is-in-iframe"; type TIssueVotes = { - workspaceSlug: string; - projectId: string; + anchor: string; }; export const IssueVotes: React.FC = observer((props) => { + const { anchor } = props; + // states + const [isSubmitting, setIsSubmitting] = useState(false); + // router const router = useRouter(); const pathName = usePathname(); const searchParams = useSearchParams(); @@ -26,11 +29,7 @@ export const IssueVotes: React.FC = observer((props) => { const state = searchParams.get("state") || undefined; const priority = searchParams.get("priority") || undefined; const labels = searchParams.get("labels") || undefined; - - const { workspaceSlug, projectId } = props; - // states - const [isSubmitting, setIsSubmitting] = useState(false); - + // store hooks const issueDetailsStore = useIssueDetails(); const { data: user } = useUser(); @@ -47,18 +46,18 @@ export const IssueVotes: React.FC = observer((props) => { const isDownVotedByUser = allDownVotes?.some((vote) => vote.actor === user?.id); const handleVote = async (e: any, voteValue: 1 | -1) => { - if (!workspaceSlug || !projectId || !issueId) return; + if (!issueId) return; setIsSubmitting(true); const actionPerformed = votes?.find((vote) => vote.actor === user?.id && vote.vote === voteValue); - if (actionPerformed) - await issueDetailsStore.removeIssueVote(workspaceSlug.toString(), projectId.toString(), issueId); - else - await issueDetailsStore.addIssueVote(workspaceSlug.toString(), projectId.toString(), issueId, { + if (actionPerformed) await issueDetailsStore.removeIssueVote(anchor, issueId); + else { + await issueDetailsStore.addIssueVote(anchor, issueId, { vote: voteValue, }); + } setIsSubmitting(false); }; diff --git a/space/components/issues/peek-overview/side-peek-view.tsx b/space/components/issues/peek-overview/side-peek-view.tsx index 4c650be6c..b464a065a 100644 --- a/space/components/issues/peek-overview/side-peek-view.tsx +++ b/space/components/issues/peek-overview/side-peek-view.tsx @@ -32,7 +32,7 @@ export const SidePeekView: React.FC = observer((props) => {
{/* issue title and description */}
- +
{/* issue properties */}
diff --git a/space/components/views/project-details.tsx b/space/components/views/project-details.tsx index c4fdef1f6..27fb3b7ce 100644 --- a/space/components/views/project-details.tsx +++ b/space/components/views/project-details.tsx @@ -33,11 +33,12 @@ export const ProjectDetailsView: FC = observer((props) const priority = searchParams.get("priority") || undefined; const labels = searchParams.get("labels") || undefined; // store hooks - const { issueFilters } = useIssueFilter(); + const { getIssueFilters } = useIssueFilter(); const { loader, issues, error, fetchPublicIssues } = useIssue(); const issueDetailStore = useIssueDetails(); // derived values const { anchor } = publishSettings; + const issueFilters = anchor ? getIssueFilters(anchor) : undefined; useSWR( anchor ? `PUBLIC_ISSUES_${anchor}` : null, diff --git a/space/hooks/store/use-project.ts b/space/hooks/store/use-project.ts deleted file mode 100644 index cd3e28958..000000000 --- a/space/hooks/store/use-project.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useContext } from "react"; -// lib -import { StoreContext } from "@/lib/store-provider"; -// store -import { IProjectStore } from "@/store/project.store"; - -export const useProject = (): IProjectStore => { - const context = useContext(StoreContext); - if (context === undefined) throw new Error("useUserProfile must be used within StoreProvider"); - return context.project; -}; diff --git a/space/services/file.service.ts b/space/services/file.service.ts index 0e277af1e..9fe06cd36 100644 --- a/space/services/file.service.ts +++ b/space/services/file.service.ts @@ -4,30 +4,6 @@ import { API_BASE_URL } from "@/helpers/common.helper"; // services import { APIService } from "@/services/api.service"; -interface UnSplashImage { - id: string; - created_at: Date; - updated_at: Date; - promoted_at: Date; - width: number; - height: number; - color: string; - blur_hash: string; - description: null; - alt_description: string; - urls: UnSplashImageUrls; - [key: string]: any; -} - -interface UnSplashImageUrls { - raw: string; - full: string; - regular: string; - small: string; - thumb: string; - small_s3: string; -} - class FileService extends APIService { private cancelSource: any; @@ -123,40 +99,6 @@ class FileService extends APIService { throw error?.response?.data; }); } - - async deleteFile(workspaceId: string, assetUrl: string): Promise { - const lastIndex = assetUrl.lastIndexOf("/"); - const assetId = assetUrl.substring(lastIndex + 1); - - return this.delete(`/api/workspaces/file-assets/${workspaceId}/${assetId}/`) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async uploadUserFile(file: FormData): Promise { - return this.post(`/api/users/file-assets/`, file, { - headers: { - "Content-Type": "multipart/form-data", - }, - }) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async deleteUserFile(assetUrl: string): Promise { - const lastIndex = assetUrl.lastIndexOf("/"); - const assetId = assetUrl.substring(lastIndex + 1); - - return this.delete(`/api/users/file-assets/${assetId}`) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } } const fileService = new FileService(); diff --git a/space/store/issue-filters.store.ts b/space/store/issue-filters.store.ts index b7b311af4..daf797f90 100644 --- a/space/store/issue-filters.store.ts +++ b/space/store/issue-filters.store.ts @@ -1,7 +1,7 @@ import cloneDeep from "lodash/cloneDeep"; import isEqual from "lodash/isEqual"; import set from "lodash/set"; -import { action, makeObservable, observable, runInAction, computed } from "mobx"; +import { action, makeObservable, observable, runInAction } from "mobx"; import { computedFn } from "mobx-utils"; // constants import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue"; @@ -19,16 +19,17 @@ import { export interface IIssueFilterStore { // observables layoutOptions: TIssueLayoutOptions; - filters: { [projectId: string]: TIssueFilters } | undefined; + filters: { [anchor: string]: TIssueFilters } | undefined; // computed - issueFilters: TIssueFilters | undefined; - appliedFilters: TIssueQueryFiltersParams | undefined; - isIssueFiltersUpdated: (filters: TIssueFilters) => boolean; + isIssueFiltersUpdated: (anchor: string, filters: TIssueFilters) => boolean; + // helpers + getIssueFilters: (anchor: string) => TIssueFilters | undefined; + getAppliedFilters: (anchor: string) => TIssueQueryFiltersParams | undefined; // actions updateLayoutOptions: (layout: TIssueLayoutOptions) => void; - initIssueFilters: (projectId: string, filters: TIssueFilters) => void; + initIssueFilters: (anchor: string, filters: TIssueFilters) => void; updateIssueFilters: ( - projectId: string, + anchor: string, filterKind: K, filterKey: keyof TIssueFilters[K], filters: TIssueFilters[K][typeof filterKey] @@ -44,16 +45,13 @@ export class IssueFilterStore implements IIssueFilterStore { gantt: false, spreadsheet: false, }; - filters: { [projectId: string]: TIssueFilters } | undefined = undefined; + filters: { [anchor: string]: TIssueFilters } | undefined = undefined; constructor(private store: RootStore) { makeObservable(this, { // observables layoutOptions: observable, filters: observable, - // computed - issueFilters: computed, - appliedFilters: computed, // actions updateLayoutOptions: action, initIssueFilters: action, @@ -82,79 +80,70 @@ export class IssueFilterStore implements IIssueFilterStore { }; // computed - get issueFilters() { - const projectId = this.store.project.project?.id; - if (!projectId) return undefined; - - const currentFilters = this.filters?.[projectId]; - if (!currentFilters) return undefined; - + getIssueFilters = computedFn((anchor: string) => { + const currentFilters = this.filters?.[anchor]; return currentFilters; - } + }); - get appliedFilters() { - const currentIssueFilters = this.issueFilters; - if (!currentIssueFilters) return undefined; + getAppliedFilters = computedFn((anchor: string) => { + const issueFilters = this.getIssueFilters(anchor); + if (!issueFilters) return undefined; - const currentLayout = currentIssueFilters?.display_filters?.layout; + const currentLayout = issueFilters?.display_filters?.layout; if (!currentLayout) return undefined; const currentFilters: TIssueQueryFilters = { - priority: currentIssueFilters?.filters?.priority || undefined, - state: currentIssueFilters?.filters?.state || undefined, - labels: currentIssueFilters?.filters?.labels || undefined, + priority: issueFilters?.filters?.priority || undefined, + state: issueFilters?.filters?.state || undefined, + labels: issueFilters?.filters?.labels || undefined, }; const filteredParams = ISSUE_DISPLAY_FILTERS_BY_LAYOUT?.[currentLayout]?.filters || []; const currentFilterQueryParams: TIssueQueryFiltersParams = this.computedFilter(currentFilters, filteredParams); return currentFilterQueryParams; - } + }); - isIssueFiltersUpdated = computedFn((userFilters: TIssueFilters) => { - if (!this.issueFilters) return false; + isIssueFiltersUpdated = computedFn((anchor: string, userFilters: TIssueFilters) => { + const issueFilters = this.getIssueFilters(anchor); + if (!issueFilters) return false; const currentUserFilters = cloneDeep(userFilters?.filters || {}); - const currentIssueFilters = cloneDeep(this.issueFilters?.filters || {}); + const currentIssueFilters = cloneDeep(issueFilters?.filters || {}); return isEqual(currentUserFilters, currentIssueFilters); }); // actions updateLayoutOptions = (options: TIssueLayoutOptions) => set(this, ["layoutOptions"], options); - initIssueFilters = async (projectId: string, initFilters: TIssueFilters) => { + initIssueFilters = async (anchor: string, initFilters: TIssueFilters) => { try { - if (!projectId) return; if (this.filters === undefined) runInAction(() => (this.filters = {})); - if (this.filters && initFilters) set(this.filters, [projectId], initFilters); + if (this.filters && initFilters) set(this.filters, [anchor], initFilters); - const workspaceSlug = this.store.project.workspace?.slug; - const currentAppliedFilters = this.appliedFilters; + const appliedFilters = this.getAppliedFilters(anchor); - if (!workspaceSlug) return; - await this.store.issue.fetchPublicIssues(workspaceSlug, projectId, currentAppliedFilters); + await this.store.issue.fetchPublicIssues(anchor, appliedFilters); } catch (error) { throw error; } }; updateIssueFilters = async ( - projectId: string, + anchor: string, filterKind: K, filterKey: keyof TIssueFilters[K], filterValue: TIssueFilters[K][typeof filterKey] ) => { try { - if (!projectId || !filterKind || !filterKey || !filterValue) return; + if (!filterKind || !filterKey || !filterValue) return; if (this.filters === undefined) runInAction(() => (this.filters = {})); runInAction(() => { - if (this.filters) set(this.filters, [projectId, filterKind, filterKey], filterValue); + if (this.filters) set(this.filters, [anchor, filterKind, filterKey], filterValue); }); - const workspaceSlug = this.store.project.workspace?.slug; - const currentAppliedFilters = this.appliedFilters; + const appliedFilters = this.getAppliedFilters(anchor); - if (!workspaceSlug) return; - await this.store.issue.fetchPublicIssues(workspaceSlug, projectId, currentAppliedFilters); + await this.store.issue.fetchPublicIssues(anchor, appliedFilters); } catch (error) { throw error; } diff --git a/space/store/project.store.ts b/space/store/project.store.ts deleted file mode 100644 index 04ef4182c..000000000 --- a/space/store/project.store.ts +++ /dev/null @@ -1,96 +0,0 @@ -// mobx -import { observable, action, makeObservable, runInAction, computed } from "mobx"; -// service -import ProjectService from "@/services/project.service"; -// store types -import { RootStore } from "@/store/root.store"; -// types -import { TWorkspaceDetails, TProjectDetails, TProjectSettings } from "@/types/project"; - -export interface IProjectStore { - // observables - loader: boolean; - error: any | undefined; - settings: TProjectSettings | undefined; - workspace: TWorkspaceDetails | undefined; - projectMap: Record; // { [projectID]: TProjectDetails } - canReact: boolean; - canComment: boolean; - canVote: boolean; - // actions - fetchProjectSettings: (workspaceSlug: string, project_slug: string) => Promise; - hydrate: (projectSettings: any) => void; -} - -export class ProjectStore implements IProjectStore { - // observables - loader: boolean = false; - error: any | undefined = undefined; - settings: TProjectSettings | undefined = undefined; - workspace: TWorkspaceDetails | undefined = undefined; - projectMap: Record = {}; - // service - projectService; - - constructor(private store: RootStore) { - makeObservable(this, { - // loaders and error observables - loader: observable, - error: observable.ref, - // observable - workspace: observable, - projectMap: observable, - settings: observable, - // computed - canReact: computed, - canComment: computed, - canVote: computed, - // actions - fetchProjectSettings: action, - hydrate: action, - }); - // services - this.projectService = new ProjectService(); - } - - // computed - get canReact() { - return this.settings?.reactions ?? false; - } - get canComment() { - return this.settings?.comments ?? false; - } - get canVote() { - return this.settings?.votes ?? false; - } - - fetchProjectSettings = async (workspaceSlug: string, project_slug: string) => { - try { - this.loader = true; - this.error = null; - - const response = await this.projectService.getProjectSettings(workspaceSlug, project_slug); - - if (response) { - this.store.issueFilter.updateLayoutOptions(response?.views); - runInAction(() => { - this.project = response?.project_details; - this.workspace = response?.workspace_detail; - this.settings = response; - this.loader = false; - }); - } - return response; - } catch (error) { - this.loader = false; - this.error = error; - return error; - } - }; - - hydrate = (projectSettings: TProjectSettings) => { - const { workspace_detail, project_details } = projectSettings; - this.workspace = workspace_detail; - this.project = project_details; - }; -} diff --git a/space/store/publish/publish.store.ts b/space/store/publish/publish.store.ts index 36616bb91..5d45a0249 100644 --- a/space/store/publish/publish.store.ts +++ b/space/store/publish/publish.store.ts @@ -8,6 +8,9 @@ import { TPublishSettings } from "@/types/publish"; export interface IPublishStore extends TPublishSettings { // computed workspaceSlug: string | undefined; + canComment: boolean; + canReact: boolean; + canVote: boolean; } export class PublishStore implements IPublishStore { @@ -67,10 +70,37 @@ export class PublishStore implements IPublishStore { workspace_detail: observable, // computed workspaceSlug: computed, + canComment: computed, + canReact: computed, + canVote: computed, }); } + /** + * @description returns the workspace slug from the workspace details + */ get workspaceSlug() { return this?.workspace_detail?.slug ?? undefined; } + + /** + * @description returns whether commenting is enabled or not + */ + get canComment() { + return !!this.comments; + } + + /** + * @description returns whether reacting is enabled or not + */ + get canReact() { + return !!this.reactions; + } + + /** + * @description returns whether voting is enabled or not + */ + get canVote() { + return !!this.votes; + } }