-
+
+
+
+
+
>
)}
>
diff --git a/space/components/views/project-details.tsx b/space/components/views/project-details.tsx
index ef51a4512..f0fff758c 100644
--- a/space/components/views/project-details.tsx
+++ b/space/components/views/project-details.tsx
@@ -1,7 +1,10 @@
-import { useEffect } from "react";
+"use client";
+
+import { FC, useEffect } from "react";
import { observer } from "mobx-react-lite";
import Image from "next/image";
-import { useRouter } from "next/router";
+import { useParams } from "next/navigation";
+import useSWR from "swr";
// components
import { IssueCalendarView } from "@/components/issues/board-views/calendar";
import { IssueGanttView } from "@/components/issues/board-views/gantt";
@@ -11,16 +14,31 @@ import { IssueSpreadsheetView } from "@/components/issues/board-views/spreadshee
import { IssueAppliedFilters } from "@/components/issues/filters/applied-filters/root";
import { IssuePeekOverview } from "@/components/issues/peek-overview";
// mobx store
-import { useMobxStore, useUser } from "@/hooks/store";
-import { RootStore } from "@/store/root.store";
+import { useIssue, useUser, useProject, useIssueDetails } from "@/hooks/store";
// assets
import SomethingWentWrongImage from "public/something-went-wrong.svg";
-export const ProjectDetailsView = observer(() => {
- const router = useRouter();
- const { workspace_slug, project_slug, states, labels, priorities, peekId } = router.query;
+type ProjectDetailsViewProps = {
+ workspaceSlug: string;
+ projectId: string;
+ peekId: string;
+};
- const { issue: issueStore, project: projectStore, issueDetails: issueDetailStore }: RootStore = useMobxStore();
+export const ProjectDetailsView: FC
= observer((props) => {
+ const { workspaceSlug, projectId, peekId } = props;
+ // router
+ const params = useParams();
+ // store hooks
+ const { fetchPublicIssues } = useIssue();
+ const { activeLayout } = useProject();
+ // fetching public issues
+ useSWR(
+ workspaceSlug && projectId ? "PROJECT_PUBLIC_ISSUES" : null,
+ workspaceSlug && projectId ? () => fetchPublicIssues(workspaceSlug, projectId, params) : null
+ );
+ // store hooks
+ const issueStore = useIssue();
+ const issueDetailStore = useIssueDetails();
const { data: currentUser, fetchCurrentUser } = useUser();
useEffect(() => {
@@ -30,25 +48,14 @@ export const ProjectDetailsView = observer(() => {
}, [currentUser, fetchCurrentUser]);
useEffect(() => {
- if (workspace_slug && project_slug) {
- const params = {
- state: states || null,
- labels: labels || null,
- priority: priorities || null,
- };
- issueStore.fetchPublicIssues(workspace_slug?.toString(), project_slug.toString(), params);
- }
- }, [workspace_slug, project_slug, issueStore, states, labels, priorities]);
-
- useEffect(() => {
- if (peekId && workspace_slug && project_slug) {
+ if (peekId && workspaceSlug && projectId) {
issueDetailStore.setPeekId(peekId.toString());
}
- }, [peekId, issueDetailStore, project_slug, workspace_slug]);
+ }, [peekId, issueDetailStore, projectId, workspaceSlug]);
return (
- {workspace_slug &&
}
+ {workspaceSlug &&
}
{issueStore?.loader && !issueStore.issues ? (
Loading...
@@ -67,24 +74,24 @@ export const ProjectDetailsView = observer(() => {
) : (
- projectStore?.activeBoard && (
+ activeLayout && (
{/* applied filters */}
- {projectStore?.activeBoard === "list" && (
+ {activeLayout === "list" && (
-
+
)}
- {projectStore?.activeBoard === "kanban" && (
+ {activeLayout === "kanban" && (
-
+
)}
- {projectStore?.activeBoard === "calendar" &&
}
- {projectStore?.activeBoard === "spreadsheet" &&
}
- {projectStore?.activeBoard === "gantt" &&
}
+ {activeLayout === "calendar" &&
}
+ {activeLayout === "spreadsheet" &&
}
+ {activeLayout === "gantt" &&
}
)
)}
diff --git a/space/constants/issue.ts b/space/constants/issue.ts
new file mode 100644
index 000000000..147d840fc
--- /dev/null
+++ b/space/constants/issue.ts
@@ -0,0 +1,20 @@
+import { ILayoutDisplayFiltersOptions } from "@/types/issue-filters";
+
+export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: {
+ [pageType: string]: { [layoutType: string]: ILayoutDisplayFiltersOptions };
+} = {
+ issues: {
+ list: {
+ filters: ["priority", "state", "labels"],
+ display_properties: null,
+ display_filters: null,
+ extra_options: null,
+ },
+ kanban: {
+ filters: ["priority", "state", "labels"],
+ display_properties: null,
+ display_filters: null,
+ extra_options: null,
+ },
+ },
+};
diff --git a/space/hooks/store/index.ts b/space/hooks/store/index.ts
index 3b7ef07c9..76b6f9315 100644
--- a/space/hooks/store/index.ts
+++ b/space/hooks/store/index.ts
@@ -1,4 +1,7 @@
-export * from "./user-mobx-provider";
-
export * from "./use-instance";
-export * from "./user";
+export * from "./use-project";
+export * from "./use-issue";
+export * from "./use-user";
+export * from "./use-user-profile";
+export * from "./use-issue-details";
+export * from "./use-issue-filter";
diff --git a/space/hooks/store/use-instance.ts b/space/hooks/store/use-instance.ts
index 92165e2bb..62aa0baae 100644
--- a/space/hooks/store/use-instance.ts
+++ b/space/hooks/store/use-instance.ts
@@ -1,10 +1,11 @@
import { useContext } from "react";
+// lib
+import { StoreContext } from "@/lib/app-providers";
// store
-import { StoreContext } from "@/lib/store-context";
import { IInstanceStore } from "@/store/instance.store";
export const useInstance = (): IInstanceStore => {
const context = useContext(StoreContext);
- if (context === undefined) throw new Error("useInstance must be used within StoreProvider");
+ if (context === undefined) throw new Error("useUserProfile must be used within StoreProvider");
return context.instance;
};
diff --git a/space/hooks/store/use-issue-details.tsx b/space/hooks/store/use-issue-details.tsx
new file mode 100644
index 000000000..56ee48627
--- /dev/null
+++ b/space/hooks/store/use-issue-details.tsx
@@ -0,0 +1,11 @@
+import { useContext } from "react";
+// lib
+import { StoreContext } from "@/lib/app-providers";
+// store
+import { IIssueDetailStore } from "@/store/issue-detail.store";
+
+export const useIssueDetails = (): IIssueDetailStore => {
+ const context = useContext(StoreContext);
+ if (context === undefined) throw new Error("useUserProfile must be used within StoreProvider");
+ return context.issueDetail;
+};
diff --git a/space/hooks/store/use-issue-filter.ts b/space/hooks/store/use-issue-filter.ts
new file mode 100644
index 000000000..a80d9761b
--- /dev/null
+++ b/space/hooks/store/use-issue-filter.ts
@@ -0,0 +1,11 @@
+import { useContext } from "react";
+// lib
+import { StoreContext } from "@/lib/app-providers";
+// store
+import { IIssueFilterStore } from "@/store/issue-filters.store";
+
+export const useIssueFilter = (): IIssueFilterStore => {
+ const context = useContext(StoreContext);
+ if (context === undefined) throw new Error("useUserProfile must be used within StoreProvider");
+ return context.issueFilter;
+};
diff --git a/space/hooks/store/use-issue.ts b/space/hooks/store/use-issue.ts
new file mode 100644
index 000000000..8ccd95ac4
--- /dev/null
+++ b/space/hooks/store/use-issue.ts
@@ -0,0 +1,11 @@
+import { useContext } from "react";
+// lib
+import { StoreContext } from "@/lib/app-providers";
+// store
+import { IIssueStore } from "@/store/issue.store";
+
+export const useIssue = (): IIssueStore => {
+ const context = useContext(StoreContext);
+ if (context === undefined) throw new Error("useUserProfile must be used within StoreProvider");
+ return context.issue;
+};
diff --git a/space/hooks/store/use-project.ts b/space/hooks/store/use-project.ts
new file mode 100644
index 000000000..0bc7d8f8a
--- /dev/null
+++ b/space/hooks/store/use-project.ts
@@ -0,0 +1,11 @@
+import { useContext } from "react";
+// lib
+import { StoreContext } from "@/lib/app-providers";
+// 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/hooks/store/user/use-user-profile.ts b/space/hooks/store/use-user-profile.ts
similarity index 62%
rename from space/hooks/store/user/use-user-profile.ts
rename to space/hooks/store/use-user-profile.ts
index 5b1d8149d..042f16c0d 100644
--- a/space/hooks/store/user/use-user-profile.ts
+++ b/space/hooks/store/use-user-profile.ts
@@ -1,10 +1,11 @@
import { useContext } from "react";
+// lib
+import { StoreContext } from "@/lib/app-providers";
// store
-import { StoreContext } from "@/lib/store-context";
-import { IProfileStore } from "@/store/user/profile.store";
+import { IProfileStore } from "@/store/profile.store";
export const useUserProfile = (): IProfileStore => {
const context = useContext(StoreContext);
if (context === undefined) throw new Error("useUserProfile must be used within StoreProvider");
- return context.user.userProfile;
+ return context.user.profile;
};
diff --git a/space/hooks/store/user/use-user.ts b/space/hooks/store/use-user.ts
similarity index 69%
rename from space/hooks/store/user/use-user.ts
rename to space/hooks/store/use-user.ts
index e491d88a2..c935946f8 100644
--- a/space/hooks/store/user/use-user.ts
+++ b/space/hooks/store/use-user.ts
@@ -1,7 +1,8 @@
import { useContext } from "react";
+// lib
+import { StoreContext } from "@/lib/app-providers";
// store
-import { StoreContext } from "@/lib/store-context";
-import { IUserStore } from "@/store/user";
+import { IUserStore } from "@/store/user.store";
export const useUser = (): IUserStore => {
const context = useContext(StoreContext);
diff --git a/space/hooks/store/user-mobx-provider.ts b/space/hooks/store/user-mobx-provider.ts
deleted file mode 100644
index 4fbc5591f..000000000
--- a/space/hooks/store/user-mobx-provider.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { useContext } from "react";
-// store
-import { StoreContext } from "@/lib/store-context";
-import { RootStore } from "@/store/root.store";
-
-export const useMobxStore = (): RootStore => {
- const context = useContext(StoreContext);
- if (context === undefined) throw new Error("useMobxStore must be used within StoreProvider");
- return context;
-};
diff --git a/space/hooks/store/user/index.ts b/space/hooks/store/user/index.ts
deleted file mode 100644
index 72660f100..000000000
--- a/space/hooks/store/user/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from "./use-user";
-export * from "./use-user-profile";
diff --git a/space/hooks/use-editor-suggestions.tsx b/space/hooks/use-editor-suggestions.tsx
deleted file mode 100644
index 937306f7b..000000000
--- a/space/hooks/use-editor-suggestions.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { useMobxStore } from "@/hooks/store";
-import { RootStore } from "@/store/root.store";
-
-const useEditorSuggestions = () => {
- const { mentionsStore }: RootStore = useMobxStore();
-
- return {
- // mentionSuggestions: mentionsStore.mentionSuggestions,
- mentionHighlights: mentionsStore.mentionHighlights,
- };
-};
-
-export default useEditorSuggestions;
diff --git a/space/layouts/project-layout.tsx b/space/layouts/project-layout.tsx
deleted file mode 100644
index 0411bcbcc..000000000
--- a/space/layouts/project-layout.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { observer } from "mobx-react-lite";
-import Image from "next/image";
-// components
-import IssueNavbar from "@/components/issues/navbar";
-// logo
-import planeLogo from "public/plane-logo.svg";
-
-const ProjectLayout = ({ children }: { children: React.ReactNode }) => (
-
-);
-
-export default observer(ProjectLayout);
diff --git a/space/lib/app-providers.tsx b/space/lib/app-providers.tsx
new file mode 100644
index 000000000..389d68ab2
--- /dev/null
+++ b/space/lib/app-providers.tsx
@@ -0,0 +1,38 @@
+"use client";
+
+import { ReactNode, createContext } from "react";
+import { ThemeProvider } from "next-themes";
+// store
+import { RootStore } from "@/store/root.store";
+
+let rootStore = new RootStore();
+
+export const StoreContext = createContext(rootStore);
+
+function initializeStore(initialData = {}) {
+ const singletonRootStore = rootStore ?? new RootStore();
+ // If your page has Next.js data fetching methods that use a Mobx store, it will
+ // get hydrated here, check `pages/ssg.js` and `pages/ssr.js` for more details
+ if (initialData) {
+ singletonRootStore.hydrate(initialData);
+ }
+ // For SSG and SSR always create a new store
+ if (typeof window === "undefined") return singletonRootStore;
+ // Create the store once in the client
+ if (!rootStore) rootStore = singletonRootStore;
+ return singletonRootStore;
+}
+
+export type AppProviderProps = {
+ children: ReactNode;
+ initialState: any;
+};
+
+export const AppProvider = ({ children, initialState = {} }: AppProviderProps) => {
+ const store = initializeStore(initialState);
+ return (
+
+ {children}
+
+ );
+};
diff --git a/space/lib/index.ts b/space/lib/index.ts
deleted file mode 100644
index a10356821..000000000
--- a/space/lib/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const init = {};
diff --git a/space/lib/store-context.tsx b/space/lib/store-context.tsx
deleted file mode 100644
index 1eff1ddde..000000000
--- a/space/lib/store-context.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { ReactElement, createContext } from "react";
-// mobx store
-import { RootStore } from "@/store/root.store";
-
-export let rootStore = new RootStore();
-
-export const StoreContext = createContext
(rootStore);
-
-const initializeStore = () => {
- const singletonRootStore = rootStore ?? new RootStore();
- if (typeof window === "undefined") return singletonRootStore;
- if (!rootStore) rootStore = singletonRootStore;
- return singletonRootStore;
-};
-
-export const StoreProvider = ({ children }: { children: ReactElement }) => {
- const store = initializeStore();
- return {children};
-};
diff --git a/space/lib/wrappers/auth-wrapper.tsx b/space/lib/wrappers/auth-wrapper.tsx
index 3b49e80d5..ba1fae2e5 100644
--- a/space/lib/wrappers/auth-wrapper.tsx
+++ b/space/lib/wrappers/auth-wrapper.tsx
@@ -1,6 +1,6 @@
import { FC, ReactNode } from "react";
import { observer } from "mobx-react-lite";
-import { useRouter } from "next/router";
+import { useRouter } from "next/navigation";
import useSWR from "swr";
import { Spinner } from "@plane/ui";
// helpers
diff --git a/space/lib/wrappers/index.ts b/space/lib/wrappers/index.ts
index 51fab70a6..d40c4c886 100644
--- a/space/lib/wrappers/index.ts
+++ b/space/lib/wrappers/index.ts
@@ -1,2 +1 @@
-export * from "./instance-wrapper";
export * from "./auth-wrapper";
diff --git a/space/lib/wrappers/instance-wrapper.tsx b/space/lib/wrappers/instance-wrapper.tsx
deleted file mode 100644
index 3be92ed05..000000000
--- a/space/lib/wrappers/instance-wrapper.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { FC, ReactNode } from "react";
-import { observer } from "mobx-react-lite";
-import useSWR from "swr";
-// ui
-import { Spinner } from "@plane/ui";
-// components
-import { InstanceNotReady, InstanceFailureView } from "@/components/instance";
-// hooks
-import { useInstance } from "@/hooks/store";
-
-type TInstanceWrapper = {
- children: ReactNode;
-};
-
-export const InstanceWrapper: FC = observer((props) => {
- const { children } = props;
- // hooks
- const { isLoading, instance, fetchInstanceInfo } = useInstance();
-
- const { isLoading: isSWRLoading, mutate } = useSWR("INSTANCE_INFORMATION", () => fetchInstanceInfo(), {
- revalidateOnFocus: false,
- revalidateIfStale: false,
- revalidateOnReconnect: false,
- errorRetryCount: 0,
- });
-
- if (isSWRLoading || isLoading)
- return (
-
-
-
- );
-
- if (!instance) return ;
-
- if (instance?.instance?.is_setup_done === false) return ;
-
- return <>{children}>;
-});
diff --git a/space/pages/404.tsx b/space/pages/404.tsx
deleted file mode 100644
index 4591f71f8..000000000
--- a/space/pages/404.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-// next imports
-import { observer } from "mobx-react-lite";
-import Image from "next/image";
-// hooks
-import { useInstance } from "@/hooks/store";
-// images
-import notFoundImage from "public/404.svg";
-
-const Custom404Error = observer(() => {
- // hooks
- const { instance } = useInstance();
-
- const redirectionUrl = instance?.config?.app_base_url || "/";
-
- return (
-
-
-
-
-
-
-
Oops! Something went wrong.
-
- Sorry, the page you are looking for cannot be found. It may have been removed, had its name changed, or is
- temporarily unavailable.
-
-
-
-
-
-
- );
-});
-
-export default Custom404Error;
diff --git a/space/pages/[workspace_slug]/[project_slug]/index.tsx b/space/pages/[workspace_slug]/[project_slug]/index.tsx
deleted file mode 100644
index aaec7672e..000000000
--- a/space/pages/[workspace_slug]/[project_slug]/index.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import Head from "next/head";
-import { useRouter } from "next/router";
-import useSWR from "swr";
-// components
-import { ProjectDetailsView } from "@/components/views";
-// helpers
-import { EPageTypes } from "@/helpers/authentication.helper";
-// hooks
-import { useMobxStore } from "@/hooks/store";
-// layouts
-import ProjectLayout from "@/layouts/project-layout";
-// wrappers
-import { AuthWrapper } from "@/lib/wrappers";
-
-const WorkspaceProjectPage = (props: any) => {
- const SITE_TITLE = props?.project_settings?.project_details?.name || "Plane | Deploy";
-
- const router = useRouter();
- const { workspace_slug, project_slug, states, labels, priorities } = router.query;
-
- const { project: projectStore, issue: issueStore } = useMobxStore();
-
- useSWR("REVALIDATE_ALL", () => {
- if (workspace_slug && project_slug) {
- projectStore.fetchProjectSettings(workspace_slug.toString(), project_slug.toString());
- const params = {
- state: states || null,
- labels: labels || null,
- priority: priorities || null,
- };
- issueStore.fetchPublicIssues(workspace_slug.toString(), project_slug.toString(), params);
- }
- });
-
- return (
-
-
-
- {SITE_TITLE}
-
-
-
-
- );
-};
-
-export default WorkspaceProjectPage;
diff --git a/space/pages/[workspace_slug]/index.tsx b/space/pages/[workspace_slug]/index.tsx
deleted file mode 100644
index 635f3fdf9..000000000
--- a/space/pages/[workspace_slug]/index.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-const WorkspaceProjectPage = () => (
- Plane Workspace Space
-);
-
-export default WorkspaceProjectPage;
diff --git a/space/pages/_app.tsx b/space/pages/_app.tsx
deleted file mode 100644
index 363b61510..000000000
--- a/space/pages/_app.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import type { AppProps } from "next/app";
-import Head from "next/head";
-import { ThemeProvider } from "next-themes";
-// styles
-import "@/styles/globals.css";
-// contexts
-import { SITE_NAME, SITE_DESCRIPTION, SITE_URL, TWITTER_USER_NAME, SITE_KEYWORDS, SITE_TITLE } from "@/constants/seo";
-import { ToastContextProvider } from "@/contexts/toast.context";
-// mobx store provider
-import { StoreProvider } from "@/lib/store-context";
-// wrappers
-import { InstanceWrapper } from "@/lib/wrappers";
-
-const prefix = "/spaces/";
-
-function MyApp({ Component, pageProps }: AppProps) {
- return (
- <>
-
- {SITE_TITLE}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-}
-
-export default MyApp;
diff --git a/space/pages/_document.tsx b/space/pages/_document.tsx
deleted file mode 100644
index ae4455438..000000000
--- a/space/pages/_document.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import Document, { Html, Head, Main, NextScript } from "next/document";
-
-class MyDocument extends Document {
- render() {
- return (
-
-
-
-
-
-
-
-
- );
- }
-}
-
-export default MyDocument;
diff --git a/space/pages/accounts/forgot-password.tsx b/space/pages/accounts/forgot-password.tsx
deleted file mode 100644
index 494eae9d3..000000000
--- a/space/pages/accounts/forgot-password.tsx
+++ /dev/null
@@ -1,166 +0,0 @@
-import { NextPage } from "next";
-import Image from "next/image";
-import Link from "next/link";
-import { useRouter } from "next/router";
-import { useTheme } from "next-themes";
-import { Controller, useForm } from "react-hook-form";
-// icons
-import { CircleCheck } from "lucide-react";
-// ui
-import { Button, Input, TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui";
-// helpers
-import { EPageTypes } from "@/helpers/authentication.helper";
-import { cn } from "@/helpers/common.helper";
-import { checkEmailValidity } from "@/helpers/string.helper";
-// hooks
-import useTimer from "@/hooks/use-timer";
-// wrappers
-import { AuthWrapper } from "@/lib/wrappers";
-// services
-import { AuthService } from "@/services/authentication.service";
-// images
-import PlaneBackgroundPatternDark from "public/auth/background-pattern-dark.svg";
-import PlaneBackgroundPattern from "public/auth/background-pattern.svg";
-import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
-
-type TForgotPasswordFormValues = {
- email: string;
-};
-
-const defaultValues: TForgotPasswordFormValues = {
- email: "",
-};
-
-// services
-const authService = new AuthService();
-
-const ForgotPasswordPage: NextPage = () => {
- // router
- const router = useRouter();
- const { email } = router.query;
- // hooks
- const { resolvedTheme } = useTheme();
- // timer
- const { timer: resendTimerCode, setTimer: setResendCodeTimer } = useTimer(0);
-
- // form info
- const {
- control,
- formState: { errors, isSubmitting, isValid },
- handleSubmit,
- } = useForm({
- defaultValues: {
- ...defaultValues,
- email: email?.toString() ?? "",
- },
- });
-
- const handleForgotPassword = async (formData: TForgotPasswordFormValues) => {
- await authService
- .sendResetPasswordLink({
- email: formData.email,
- })
- .then(() => {
- setToast({
- type: TOAST_TYPE.SUCCESS,
- title: "Email sent",
- message:
- "Check your inbox for a link to reset your password. If it doesn't appear within a few minutes, check your spam folder.",
- });
- setResendCodeTimer(30);
- })
- .catch((err: any) => {
- setToast({
- type: TOAST_TYPE.ERROR,
- title: "Error!",
- message: err?.error ?? "Something went wrong. Please try again.",
- });
- });
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- Reset your password
-
-
- Enter your user account{"'"}s verified email address and we will send you a password reset link.
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default ForgotPasswordPage;
diff --git a/space/pages/accounts/reset-password.tsx b/space/pages/accounts/reset-password.tsx
deleted file mode 100644
index 773acb10e..000000000
--- a/space/pages/accounts/reset-password.tsx
+++ /dev/null
@@ -1,205 +0,0 @@
-import { useEffect, useMemo, useState } from "react";
-import { NextPage } from "next";
-import Image from "next/image";
-import { useRouter } from "next/router";
-// icons
-import { useTheme } from "next-themes";
-import { Eye, EyeOff } from "lucide-react";
-// ui
-import { Button, Input } from "@plane/ui";
-// components
-import { PasswordStrengthMeter } from "@/components/accounts";
-// helpers
-import { EPageTypes } from "@/helpers/authentication.helper";
-import { API_BASE_URL } from "@/helpers/common.helper";
-import { getPasswordStrength } from "@/helpers/password.helper";
-// wrappers
-import { AuthWrapper } from "@/lib/wrappers";
-// services
-import { AuthService } from "@/services/authentication.service";
-// images
-import PlaneBackgroundPatternDark from "public/auth/background-pattern-dark.svg";
-import PlaneBackgroundPattern from "public/auth/background-pattern.svg";
-import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
-
-type TResetPasswordFormValues = {
- email: string;
- password: string;
- confirm_password?: string;
-};
-
-const defaultValues: TResetPasswordFormValues = {
- email: "",
- password: "",
-};
-
-// services
-const authService = new AuthService();
-
-const ResetPasswordPage: NextPage = () => {
- // router
- const router = useRouter();
- const { uidb64, token, email } = router.query;
- // states
- const [showPassword, setShowPassword] = useState(false);
- const [resetFormData, setResetFormData] = useState({
- ...defaultValues,
- email: email ? email.toString() : "",
- });
- const [csrfToken, setCsrfToken] = useState(undefined);
- const [isPasswordInputFocused, setIsPasswordInputFocused] = useState(false);
- // hooks
- const { resolvedTheme } = useTheme();
-
- useEffect(() => {
- if (email && !resetFormData.email) {
- setResetFormData((prev) => ({ ...prev, email: email.toString() }));
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [email]);
-
- const handleFormChange = (key: keyof TResetPasswordFormValues, value: string) =>
- setResetFormData((prev) => ({ ...prev, [key]: value }));
-
- useEffect(() => {
- if (csrfToken === undefined)
- authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token));
- }, [csrfToken]);
-
- const isButtonDisabled = useMemo(
- () =>
- !!resetFormData.password &&
- getPasswordStrength(resetFormData.password) >= 3 &&
- resetFormData.password === resetFormData.confirm_password
- ? false
- : true,
- [resetFormData]
- );
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- Set new password
-
-
Secure your account with a strong password
-
-
-
-
-
-
-
-
- );
-};
-
-export default ResetPasswordPage;
diff --git a/space/pages/index.tsx b/space/pages/index.tsx
deleted file mode 100644
index 8bba85cca..000000000
--- a/space/pages/index.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { observer } from "mobx-react-lite";
-import { NextPage } from "next";
-// components
-import { AuthView } from "@/components/views";
-// helpers
-import { EPageTypes } from "@/helpers/authentication.helper";
-// wrapper
-import { AuthWrapper } from "@/lib/wrappers";
-
-const Index: NextPage = observer(() => (
-
-
-
-));
-
-export default Index;
diff --git a/space/pages/onboarding/index.tsx b/space/pages/onboarding/index.tsx
deleted file mode 100644
index 98404f577..000000000
--- a/space/pages/onboarding/index.tsx
+++ /dev/null
@@ -1,130 +0,0 @@
-import React from "react";
-import { observer } from "mobx-react-lite";
-import Image from "next/image";
-import { useRouter } from "next/router";
-import { useTheme } from "next-themes";
-// ui
-import { Avatar } from "@plane/ui";
-// components
-import { OnBoardingForm } from "@/components/accounts/onboarding-form";
-// helpers
-import { EPageTypes } from "@/helpers/authentication.helper";
-import { ASSET_PREFIX } from "@/helpers/common.helper";
-// hooks
-import { useUser, useUserProfile } from "@/hooks/store";
-// wrappers
-import { AuthWrapper } from "@/lib/wrappers";
-// assets
-import ProfileSetupDark from "public/onboarding/profile-setup-dark.svg";
-import ProfileSetup from "public/onboarding/profile-setup-light.svg";
-
-const OnBoardingPage = observer(() => {
- // router
- const router = useRouter();
- const { next_path } = router.query;
-
- // hooks
- const { resolvedTheme } = useTheme();
-
- const { data: user } = useUser();
- const { data: currentUserProfile, updateUserProfile } = useUserProfile();
-
- if (!user) {
- router.push("/");
- return <>>;
- }
-
- // complete onboarding
- const finishOnboarding = async () => {
- if (!user) return;
-
- await updateUserProfile({
- onboarding_step: {
- ...currentUserProfile?.onboarding_step,
- profile_complete: true,
- },
- }).catch(() => {
- console.log("Failed to update onboarding status");
- });
-
- if (next_path) router.push(next_path.toString());
- router.push("/");
- };
-
- return (
-
-
-
-
-
-
-
-
- {user?.avatar && (
-
- )}
-
- {user?.first_name ? `${user?.first_name} ${user?.last_name ?? ""}` : user?.email}
-
-
-
-
-
-
-
-
Welcome to Plane!
-
- Let’s setup your profile, tell us a bit about yourself.
-
-
-
-
-
-
-
-
- {user?.avatar && (
-
- )}
-
- {user?.first_name ? `${user?.first_name} ${user?.last_name ?? ""}` : user?.email}
-
-
-
-
-
-
-
-
-
- );
-});
-
-export default OnBoardingPage;
diff --git a/space/pages/project-not-published/index.tsx b/space/pages/project-not-published/index.tsx
deleted file mode 100644
index 0bd25dd6e..000000000
--- a/space/pages/project-not-published/index.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-// next imports
-import { observer } from "mobx-react-lite";
-import Image from "next/image";
-// helpers
-import { EPageTypes } from "@/helpers/authentication.helper";
-// hooks
-import { useInstance } from "@/hooks/store";
-// wrappers
-import { AuthWrapper } from "@/lib/wrappers";
-// images
-import projectNotPublishedImage from "@/public/project-not-published.svg";
-
-const CustomProjectNotPublishedError = observer(() => {
- // hooks
- const { instance } = useInstance();
-
- const redirectionUrl = instance?.config?.app_base_url || "/";
-
- return (
-
-
-
-
-
-
-
-
- Oops! The page you{`'`}re looking for isn{`'`}t live at the moment.
-
-
- If this is your project, login to your workspace to adjust its visibility settings and make it public.
-
-
-
-
-
-
-
- );
-});
-
-export default CustomProjectNotPublishedError;
diff --git a/space/services/api.service.ts b/space/services/api.service.ts
index b6d353ccc..a5fe3e93d 100644
--- a/space/services/api.service.ts
+++ b/space/services/api.service.ts
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import axios, { AxiosInstance } from "axios";
// store
-import { rootStore } from "@/lib/store-context";
+// import { rootStore } from "@/lib/store-context";
abstract class APIService {
protected baseURL: string;
@@ -18,14 +18,14 @@ abstract class APIService {
}
private setupInterceptors() {
- this.axiosInstance.interceptors.response.use(
- (response) => response,
- (error) => {
- const store = rootStore;
- if (error.response && error.response.status === 401 && store.user.data) store.user.reset();
- return Promise.reject(error);
- }
- );
+ // this.axiosInstance.interceptors.response.use(
+ // (response) => response,
+ // (error) => {
+ // const store = rootStore;
+ // if (error.response && error.response.status === 401 && store.user.data) store.user.reset();
+ // return Promise.reject(error);
+ // }
+ // );
}
get(url: string, params = {}) {
diff --git a/space/services/authentication.service.ts b/space/services/auth.service.ts
similarity index 100%
rename from space/services/authentication.service.ts
rename to space/services/auth.service.ts
diff --git a/space/services/issue.service.ts b/space/services/issue.service.ts
index b6f2e3be2..aa54e500e 100644
--- a/space/services/issue.service.ts
+++ b/space/services/issue.service.ts
@@ -1,6 +1,6 @@
+import { API_BASE_URL } from "@/helpers/common.helper";
// services
import APIService from "@/services/api.service";
-import { API_BASE_URL } from "@/helpers/common.helper";
class IssueService extends APIService {
constructor() {
diff --git a/space/services/project.service.ts b/space/services/project.service.ts
index 2e173d282..bff754595 100644
--- a/space/services/project.service.ts
+++ b/space/services/project.service.ts
@@ -1,6 +1,6 @@
+import { API_BASE_URL } from "@/helpers/common.helper";
// services
import APIService from "@/services/api.service";
-import { API_BASE_URL } from "@/helpers/common.helper";
class ProjectService extends APIService {
constructor() {
diff --git a/space/store/instance.store.ts b/space/store/instance.store.ts
index db4fd87a9..4a410d851 100644
--- a/space/store/instance.store.ts
+++ b/space/store/instance.store.ts
@@ -18,15 +18,18 @@ type TError = {
export interface IInstanceStore {
// issues
isLoading: boolean;
- instance: IInstance | undefined;
+ data: IInstance | NonNullable;
+ config: Record;
error: TError | undefined;
// action
fetchInstanceInfo: () => Promise;
+ hydrate: (data: Record, config: Record) => void;
}
export class InstanceStore implements IInstanceStore {
isLoading: boolean = true;
- instance: IInstance | undefined = undefined;
+ data: IInstance | Record = {};
+ config: Record = {};
error: TError | undefined = undefined;
// services
instanceService;
@@ -35,15 +38,22 @@ export class InstanceStore implements IInstanceStore {
makeObservable(this, {
// observable
isLoading: observable.ref,
- instance: observable,
+ data: observable,
+ config: observable,
error: observable,
// actions
fetchInstanceInfo: action,
+ hydrate: action,
});
// services
this.instanceService = new InstanceService();
}
+ hydrate = (data: Record, config: Record) => {
+ this.data = { ...this.data, ...data };
+ this.config = { ...this.config, ...config };
+ };
+
/**
* @description fetching instance information
*/
@@ -51,10 +61,11 @@ export class InstanceStore implements IInstanceStore {
try {
this.isLoading = true;
this.error = undefined;
- const instance = await this.instanceService.getInstanceInfo();
+ const instanceDetails = await this.instanceService.getInstanceInfo();
runInAction(() => {
this.isLoading = false;
- this.instance = instance;
+ this.data = instanceDetails.instance;
+ this.config = instanceDetails.config;
});
} catch (error) {
runInAction(() => {
diff --git a/space/store/issue_details.ts b/space/store/issue-detail.store.ts
similarity index 99%
rename from space/store/issue_details.ts
rename to space/store/issue-detail.store.ts
index 3bbf0e581..b6734640b 100644
--- a/space/store/issue_details.ts
+++ b/space/store/issue-detail.store.ts
@@ -55,7 +55,7 @@ export interface IIssueDetailStore {
removeIssueVote: (workspaceId: string, projectId: string, issueId: string) => Promise;
}
-class IssueDetailStore implements IIssueDetailStore {
+export class IssueDetailStore implements IIssueDetailStore {
loader: boolean = false;
error: any = null;
peekId: string | null = null;
@@ -431,5 +431,3 @@ class IssueDetailStore implements IIssueDetailStore {
}
};
}
-
-export default IssueDetailStore;
diff --git a/space/store/issues/issue-filters.store.ts b/space/store/issue-filters.store.ts
similarity index 55%
rename from space/store/issues/issue-filters.store.ts
rename to space/store/issue-filters.store.ts
index e62e57933..d137753be 100644
--- a/space/store/issues/issue-filters.store.ts
+++ b/space/store/issue-filters.store.ts
@@ -1,15 +1,16 @@
import { action, makeObservable, observable, runInAction, computed } from "mobx";
-// types
+// constants
+import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue";
+// store
import { RootStore } from "@/store/root.store";
-import { IIssueFilterOptions, TIssueParams } from "./types";
-import { handleIssueQueryParamsByLayout } from "./helpers";
-import { IssueFilterBaseStore } from "./base-issue-filter.store";
+// types
+import { TIssueBoardKeys, IIssueFilterOptions, TIssueParams } from "@/types/issue";
interface IFiltersOptions {
filters: IIssueFilterOptions;
}
-export interface IIssuesFilterStore {
+export interface IIssueFilterStore {
// observables
projectIssueFilters: { [projectId: string]: IFiltersOptions } | undefined;
// computed
@@ -21,15 +22,13 @@ export interface IIssuesFilterStore {
updateFilters: (projectId: string, filters: IIssueFilterOptions) => Promise;
}
-export class IssuesFilterStore extends IssueFilterBaseStore implements IIssuesFilterStore {
+export class IssueFilterStore implements IIssueFilterStore {
// observables
projectIssueFilters: { [projectId: string]: IFiltersOptions } | undefined = undefined;
// root store
rootStore;
constructor(_rootStore: RootStore) {
- super(_rootStore);
-
makeObservable(this, {
// observables
projectIssueFilters: observable.ref,
@@ -43,35 +42,61 @@ export class IssuesFilterStore extends IssueFilterBaseStore implements IIssuesFi
this.rootStore = _rootStore;
}
+ // helper methods
+ computedFilter = (filters: any, filteredParams: any) => {
+ const computedFilters: any = {};
+ Object.keys(filters).map((key) => {
+ if (filters[key] != undefined && filteredParams.includes(key))
+ computedFilters[key] =
+ typeof filters[key] === "string" || typeof filters[key] === "boolean" ? filters[key] : filters[key].join(",");
+ });
+
+ return computedFilters;
+ };
+
// helpers
issueDisplayFilters = (projectId: string) => {
if (!projectId) return undefined;
return this.projectIssueFilters?.[projectId] || undefined;
};
- // actions
+ handleIssueQueryParamsByLayout = (layout: TIssueBoardKeys | undefined, viewType: "issues"): TIssueParams[] | null => {
+ const queryParams: TIssueParams[] = [];
+ if (!layout) return null;
+
+ const layoutOptions = ISSUE_DISPLAY_FILTERS_BY_LAYOUT[viewType][layout];
+
+ // add filters query params
+ layoutOptions.filters.forEach((option: any) => {
+ queryParams.push(option);
+ });
+
+ return queryParams;
+ };
+
+ // actions
updateFilters = async (projectId: string, filters: IIssueFilterOptions) => {
try {
- let _projectIssueFilters = { ...this.projectIssueFilters };
- if (!_projectIssueFilters) _projectIssueFilters = {};
- if (!_projectIssueFilters[projectId]) _projectIssueFilters[projectId] = { filters: {} };
+ let issueFilters = { ...this.projectIssueFilters };
+ if (!issueFilters) issueFilters = {};
+ if (!issueFilters[projectId]) issueFilters[projectId] = { filters: {} };
- const _filters = {
- filters: { ..._projectIssueFilters[projectId].filters },
+ const newFilters = {
+ filters: { ...issueFilters[projectId].filters },
};
- _filters.filters = { ..._filters.filters, ...filters };
+ newFilters.filters = { ...newFilters.filters, ...filters };
- _projectIssueFilters[projectId] = {
- filters: _filters.filters,
+ issueFilters[projectId] = {
+ filters: newFilters.filters,
};
runInAction(() => {
- this.projectIssueFilters = _projectIssueFilters;
+ this.projectIssueFilters = issueFilters;
});
- return _filters;
+ return newFilters;
} catch (error) {
throw error;
}
@@ -89,7 +114,7 @@ export class IssuesFilterStore extends IssueFilterBaseStore implements IIssuesFi
get appliedFilters() {
const userFilters = this.issueFilters;
- const layout = this.rootStore.project?.activeBoard;
+ const layout = this.rootStore.project?.activeLayout;
if (!userFilters || !layout) return undefined;
let filteredRouteParams: any = {
@@ -98,7 +123,7 @@ export class IssuesFilterStore extends IssueFilterBaseStore implements IIssuesFi
labels: userFilters?.filters?.labels || undefined,
};
- const filteredParams = handleIssueQueryParamsByLayout(layout, "issues");
+ const filteredParams = this.handleIssueQueryParamsByLayout(layout, "issues");
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
return filteredRouteParams;
diff --git a/space/store/issue.ts b/space/store/issue.store.ts
similarity index 82%
rename from space/store/issue.ts
rename to space/store/issue.store.ts
index c6ed8ee71..bbaf47f79 100644
--- a/space/store/issue.ts
+++ b/space/store/issue.store.ts
@@ -1,11 +1,11 @@
-import { observable, action, computed, makeObservable, runInAction } from "mobx";
+import { observable, action, makeObservable, runInAction } from "mobx";
// services
import IssueService from "@/services/issue.service";
+// types
+import { IIssue, IIssueState, IIssueLabel } from "@/types/issue";
// store
import { RootStore } from "./root.store";
-// types
// import { IssueDetailType, TIssueBoardKeys } from "types/issue";
-import { IIssue, IIssueState, IIssueLabel } from "types/issue";
export interface IIssueStore {
loader: boolean;
@@ -26,7 +26,7 @@ export interface IIssueStore {
getFilteredIssuesByState: (state: string) => IIssue[];
}
-class IssueStore implements IIssueStore {
+export class IssueStore implements IIssueStore {
loader: boolean = false;
error: any | null = null;
@@ -75,13 +75,13 @@ class IssueStore implements IIssueStore {
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];
+ 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.states = states;
+ this.labels = labels;
+ this.issues = issues;
this.loader = false;
});
}
@@ -99,5 +99,3 @@ class IssueStore implements IIssueStore {
getFilteredIssuesByState = (state_id: string): IIssue[] | [] =>
this.issues?.filter((issue) => issue.state == state_id) || [];
}
-
-export default IssueStore;
diff --git a/space/store/issues/base-issue-filter.store.ts b/space/store/issues/base-issue-filter.store.ts
deleted file mode 100644
index d3aaae5f7..000000000
--- a/space/store/issues/base-issue-filter.store.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-// types
-import { RootStore } from "@/store/root.store";
-
-export interface IIssueFilterBaseStore {
- // helper methods
- computedFilter(filters: any, filteredParams: any): any;
-}
-
-export class IssueFilterBaseStore implements IIssueFilterBaseStore {
- // root store
- rootStore;
-
- constructor(_rootStore: RootStore) {
- // root store
- this.rootStore = _rootStore;
- }
-
- // helper methods
- computedFilter = (filters: any, filteredParams: any) => {
- const computedFilters: any = {};
- Object.keys(filters).map((key) => {
- if (filters[key] != undefined && filteredParams.includes(key))
- computedFilters[key] =
- typeof filters[key] === "string" || typeof filters[key] === "boolean" ? filters[key] : filters[key].join(",");
- });
-
- return computedFilters;
- };
-}
diff --git a/space/store/issues/helpers.ts b/space/store/issues/helpers.ts
deleted file mode 100644
index a862ca6e0..000000000
--- a/space/store/issues/helpers.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { TIssueBoardKeys } from "types/issue";
-import { IIssueFilterOptions, TIssueParams } from "./types";
-
-export const isNil = (value: any) => {
- if (value === undefined || value === null) return true;
-
- return false;
-};
-
-export interface ILayoutDisplayFiltersOptions {
- filters: (keyof IIssueFilterOptions)[];
- display_properties: boolean | null;
- display_filters: null;
- extra_options: null;
-}
-
-export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: {
- [pageType: string]: { [layoutType: string]: ILayoutDisplayFiltersOptions };
-} = {
- issues: {
- list: {
- filters: ["priority", "state", "labels"],
- display_properties: null,
- display_filters: null,
- extra_options: null,
- },
- kanban: {
- filters: ["priority", "state", "labels"],
- display_properties: null,
- display_filters: null,
- extra_options: null,
- },
- },
-};
-
-export const handleIssueQueryParamsByLayout = (
- layout: TIssueBoardKeys | undefined,
- viewType: "issues"
-): TIssueParams[] | null => {
- const queryParams: TIssueParams[] = [];
-
- if (!layout) return null;
-
- const layoutOptions = ISSUE_DISPLAY_FILTERS_BY_LAYOUT[viewType][layout];
-
- // add filters query params
- layoutOptions.filters.forEach((option) => {
- queryParams.push(option);
- });
-
- return queryParams;
-};
diff --git a/space/store/issues/types.ts b/space/store/issues/types.ts
deleted file mode 100644
index d1de0a5ea..000000000
--- a/space/store/issues/types.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { IIssue } from "types/issue";
-
-export type TIssueGroupByOptions = "state" | "priority" | "labels" | null;
-
-export type TIssueParams = "priority" | "state" | "labels";
-
-export interface IIssueFilterOptions {
- state?: string[] | null;
- labels?: string[] | null;
- priority?: string[] | null;
-}
-
-// issues
-export interface IGroupedIssues {
- [group_id: string]: string[];
-}
-
-export interface ISubGroupedIssues {
- [sub_grouped_id: string]: {
- [group_id: string]: string[];
- };
-}
-
-export type TUnGroupedIssues = string[];
-
-export interface IIssueResponse {
- [issue_id: string]: IIssue;
-}
-
-export type TLoader = "init-loader" | "mutation" | undefined;
-
-export interface ViewFlags {
- enableQuickAdd: boolean;
- enableIssueCreation: boolean;
- enableInlineEditing: boolean;
-}
diff --git a/space/store/user/profile.store.ts b/space/store/profile.store.ts
similarity index 100%
rename from space/store/user/profile.store.ts
rename to space/store/profile.store.ts
diff --git a/space/store/project.ts b/space/store/project.store.ts
similarity index 57%
rename from space/store/project.ts
rename to space/store/project.store.ts
index dd2c37c00..e382b6792 100644
--- a/space/store/project.ts
+++ b/space/store/project.store.ts
@@ -11,11 +11,15 @@ export interface IProjectStore {
error: any | null;
workspace: IWorkspace | null;
project: IProject | null;
- deploySettings: IProjectSettings | null;
- viewOptions: any;
- activeBoard: TIssueBoardKeys | null;
+ settings: IProjectSettings | null;
+ activeLayout: TIssueBoardKeys;
+ layoutOptions: Record;
+ canReact: boolean;
+ canComment: boolean;
+ canVote: boolean;
fetchProjectSettings: (workspace_slug: string, project_slug: string) => Promise;
- setActiveBoard: (value: TIssueBoardKeys) => void;
+ setActiveLayout: (value: TIssueBoardKeys) => void;
+ hydrate: (projectSettings: any) => void;
}
export class ProjectStore implements IProjectStore {
@@ -24,9 +28,18 @@ export class ProjectStore implements IProjectStore {
// data
workspace: IWorkspace | null = null;
project: IProject | null = null;
- deploySettings: IProjectSettings | null = null;
- viewOptions: any = null;
- activeBoard: TIssueBoardKeys | null = null;
+ settings: IProjectSettings | null = null;
+ activeLayout: TIssueBoardKeys = "list";
+ layoutOptions: Record = {
+ list: true,
+ kanban: true,
+ calendar: false,
+ gantt: false,
+ spreadsheet: false,
+ };
+ canReact: boolean = false;
+ canComment: boolean = false;
+ canVote: boolean = false;
// root store
rootStore;
// service
@@ -38,14 +51,18 @@ export class ProjectStore implements IProjectStore {
loader: observable,
error: observable.ref,
// observable
- workspace: observable.ref,
- project: observable.ref,
- deploySettings: observable.ref,
- viewOptions: observable.ref,
- activeBoard: observable.ref,
+ workspace: observable,
+ project: observable,
+ settings: observable,
+ layoutOptions: observable,
+ activeLayout: observable.ref,
+ canReact: observable.ref,
+ canComment: observable.ref,
+ canVote: observable.ref,
// actions
fetchProjectSettings: action,
- setActiveBoard: action,
+ setActiveLayout: action,
+ hydrate: action,
// computed
});
@@ -53,6 +70,20 @@ export class ProjectStore implements IProjectStore {
this.projectService = new ProjectService();
}
+ hydrate = (projectSettings: any) => {
+ const { workspace_detail, project_details, views, votes, comments, reactions } = projectSettings;
+ this.workspace = workspace_detail;
+ this.project = project_details;
+ this.layoutOptions = views;
+ this.canComment = comments;
+ this.canVote = votes;
+ this.canReact = reactions;
+ };
+
+ setActiveLayout = (boardValue: TIssueBoardKeys) => {
+ this.activeLayout = boardValue;
+ };
+
fetchProjectSettings = async (workspace_slug: string, project_slug: string) => {
try {
this.loader = true;
@@ -68,8 +99,8 @@ export class ProjectStore implements IProjectStore {
runInAction(() => {
this.project = currentProject;
this.workspace = currentWorkspace;
- this.viewOptions = currentViewOptions;
- this.deploySettings = currentDeploySettings;
+ this.layoutOptions = currentViewOptions;
+ this.settings = currentDeploySettings;
this.loader = false;
});
}
@@ -80,8 +111,4 @@ export class ProjectStore implements IProjectStore {
return error;
}
};
-
- setActiveBoard = (boardValue: TIssueBoardKeys) => {
- this.activeBoard = boardValue;
- };
}
diff --git a/space/store/root.store.ts b/space/store/root.store.ts
index 77fce9613..8b6b10f51 100644
--- a/space/store/root.store.ts
+++ b/space/store/root.store.ts
@@ -1,13 +1,11 @@
-// mobx lite
import { enableStaticRendering } from "mobx-react-lite";
// store imports
import { IInstanceStore, InstanceStore } from "@/store/instance.store";
-import { IProjectStore, ProjectStore } from "@/store/project";
-import { IUserStore, UserStore } from "@/store/user";
-
-import IssueStore, { IIssueStore } from "./issue";
-import IssueDetailStore, { IIssueDetailStore } from "./issue_details";
-import { IIssuesFilterStore, IssuesFilterStore } from "./issues/issue-filters.store";
+import { IssueDetailStore, IIssueDetailStore } from "@/store/issue-detail.store";
+import { IssueStore, IIssueStore } from "@/store/issue.store";
+import { IProjectStore, ProjectStore } from "@/store/project.store";
+import { IUserStore, UserStore } from "@/store/user.store";
+import { IssueFilterStore, IIssueFilterStore } from "./issue-filters.store";
import { IMentionsStore, MentionsStore } from "./mentions.store";
enableStaticRendering(typeof window === "undefined");
@@ -16,33 +14,36 @@ export class RootStore {
instance: IInstanceStore;
user: IUserStore;
project: IProjectStore;
-
issue: IIssueStore;
- issueDetails: IIssueDetailStore;
- mentionsStore: IMentionsStore;
- issuesFilter: IIssuesFilterStore;
+ issueDetail: IIssueDetailStore;
+ mentionStore: IMentionsStore;
+ issueFilter: IIssueFilterStore;
constructor() {
this.instance = new InstanceStore(this);
this.user = new UserStore(this);
-
this.project = new ProjectStore(this);
this.issue = new IssueStore(this);
- this.issueDetails = new IssueDetailStore(this);
- this.mentionsStore = new MentionsStore(this);
- this.issuesFilter = new IssuesFilterStore(this);
+ this.issueDetail = new IssueDetailStore(this);
+ this.mentionStore = new MentionsStore(this);
+ this.issueFilter = new IssueFilterStore(this);
}
- resetOnSignOut = () => {
- localStorage.setItem("theme", "system");
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ hydrate = (data: any) => {
+ if (!data) return;
+ this.instance.hydrate(data?.instance || {}, data?.config || {});
+ this.user.hydrate(data?.user || {});
+ };
+ reset = () => {
+ localStorage.setItem("theme", "system");
this.instance = new InstanceStore(this);
this.user = new UserStore(this);
this.project = new ProjectStore(this);
-
this.issue = new IssueStore(this);
- this.issueDetails = new IssueDetailStore(this);
- this.mentionsStore = new MentionsStore(this);
- this.issuesFilter = new IssuesFilterStore(this);
+ this.issueDetail = new IssueDetailStore(this);
+ this.mentionStore = new MentionsStore(this);
+ this.issueFilter = new IssueFilterStore(this);
};
}
diff --git a/space/store/user/index.ts b/space/store/user.store.ts
similarity index 90%
rename from space/store/user/index.ts
rename to space/store/user.store.ts
index e5bfc41c6..2f228b629 100644
--- a/space/store/user/index.ts
+++ b/space/store/user.store.ts
@@ -3,11 +3,11 @@ import { action, computed, makeObservable, observable, runInAction } from "mobx"
// types
import { IUser } from "@plane/types";
// services
-import { AuthService } from "@/services/authentication.service";
+import { AuthService } from "@/services/auth.service";
import { UserService } from "@/services/user.service";
// stores
import { RootStore } from "@/store/root.store";
-import { ProfileStore, IProfileStore } from "@/store/user/profile.store";
+import { ProfileStore, IProfileStore } from "@/store/profile.store";
import { ActorDetail } from "@/types/issue";
type TUserErrorStatus = {
@@ -22,12 +22,13 @@ export interface IUserStore {
error: TUserErrorStatus | undefined;
data: IUser | undefined;
// store observables
- userProfile: IProfileStore;
+ profile: IProfileStore;
// computed
currentActor: ActorDetail;
// actions
fetchCurrentUser: () => Promise;
updateCurrentUser: (data: Partial) => Promise;
+ hydrate: (data: IUser) => void;
reset: () => void;
signOut: () => Promise;
}
@@ -39,14 +40,14 @@ export class UserStore implements IUserStore {
error: TUserErrorStatus | undefined = undefined;
data: IUser | undefined = undefined;
// store observables
- userProfile: IProfileStore;
+ profile: IProfileStore;
// service
userService: UserService;
authService: AuthService;
constructor(private store: RootStore) {
// stores
- this.userProfile = new ProfileStore(store);
+ this.profile = new ProfileStore(store);
// service
this.userService = new UserService();
this.authService = new AuthService();
@@ -58,7 +59,7 @@ export class UserStore implements IUserStore {
error: observable,
// model observables
data: observable,
- userProfile: observable,
+ profile: observable,
// computed
currentActor: computed,
// actions
@@ -94,7 +95,7 @@ export class UserStore implements IUserStore {
});
const user = await this.userService.currentUser();
if (user && user?.id) {
- await this.userProfile.fetchUserProfile();
+ await this.profile.fetchUserProfile();
runInAction(() => {
this.data = user;
this.isLoading = false;
@@ -153,6 +154,10 @@ export class UserStore implements IUserStore {
}
};
+ hydrate = (data: IUser): void => {
+ this.data = { ...this.data, ...data };
+ };
+
/**
* @description resets the user store
* @returns {void}
@@ -163,7 +168,7 @@ export class UserStore implements IUserStore {
this.isLoading = false;
this.error = undefined;
this.data = undefined;
- this.userProfile = new ProfileStore(this.store);
+ this.profile = new ProfileStore(this.store);
});
};
diff --git a/space/tsconfig.json b/space/tsconfig.json
index 9d3e164be..1305e698f 100644
--- a/space/tsconfig.json
+++ b/space/tsconfig.json
@@ -1,12 +1,23 @@
{
"extends": "tsconfig/nextjs.json",
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "additional.d.ts"],
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "additional.d.ts", ".next/types/**/*.ts"],
"exclude": ["node_modules"],
"compilerOptions": {
"baseUrl": ".",
"jsx": "preserve",
"paths": {
"@/*": ["*"]
- }
+ },
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "strictNullChecks": true
}
}
diff --git a/space/types/issue-filters.d.ts b/space/types/issue-filters.d.ts
new file mode 100644
index 000000000..0ec82f40e
--- /dev/null
+++ b/space/types/issue-filters.d.ts
@@ -0,0 +1,6 @@
+export interface ILayoutDisplayFiltersOptions {
+ filters: (keyof IIssueFilterOptions)[];
+ display_properties: boolean | null;
+ display_filters: null;
+ extra_options: null;
+}
diff --git a/space/types/issue.d.ts b/space/types/issue.d.ts
index 4b76c75e8..2b7d3e673 100644
--- a/space/types/issue.d.ts
+++ b/space/types/issue.d.ts
@@ -170,3 +170,38 @@ export interface IssueDetailType {
votes: any[];
};
}
+
+export type TIssueGroupByOptions = "state" | "priority" | "labels" | null;
+
+export type TIssueParams = "priority" | "state" | "labels";
+
+export interface IIssueFilterOptions {
+ state?: string[] | null;
+ labels?: string[] | null;
+ priority?: string[] | null;
+}
+
+// issues
+export interface IGroupedIssues {
+ [group_id: string]: string[];
+}
+
+export interface ISubGroupedIssues {
+ [sub_grouped_id: string]: {
+ [group_id: string]: string[];
+ };
+}
+
+export type TUnGroupedIssues = string[];
+
+export interface IIssueResponse {
+ [issue_id: string]: IIssue;
+}
+
+export type TLoader = "init-loader" | "mutation" | undefined;
+
+export interface ViewFlags {
+ enableQuickAdd: boolean;
+ enableIssueCreation: boolean;
+ enableInlineEditing: boolean;
+}