mirror of
https://github.com/makeplane/plane.git
synced 2025-12-29 00:24:56 +01:00
fix: workspace subscription store added
This commit is contained in:
@@ -1,13 +1,101 @@
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Image from "next/image";
|
||||
import { useParams } from "next/navigation";
|
||||
import useSWR from "swr";
|
||||
// ui
|
||||
import { Tooltip } from "@plane/ui";
|
||||
import { Tooltip, Button, getButtonStyling } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useInstance, useEventTracker } from "@/hooks/store";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
// plane web components
|
||||
import { PlaneOneModal, CloudProductsModal, ProPlanDetailsModal } from "@/plane-web/components/license";
|
||||
import { useWorkspaceSubscription } from "@/plane-web/hooks/store";
|
||||
// assets
|
||||
import PlaneOneLogo from "@/public/plane-logos/plane-one.svg";
|
||||
// assets
|
||||
import packageJson from "package.json";
|
||||
|
||||
export const WorkspaceEditionBadge = observer(() => {
|
||||
// params
|
||||
const { workspaceSlug } = useParams();
|
||||
// states
|
||||
const [isProPlanModalOpen, setIsProPlanModalOpen] = useState(false);
|
||||
const [isProPlanDetailsModalOpen, setProPlanDetailsModalOpen] = useState(false);
|
||||
const [isPlaneOneModalOpen, setIsPlaneOneModalOpen] = useState(false);
|
||||
// hooks
|
||||
const { captureEvent } = useEventTracker();
|
||||
const { isMobile } = usePlatformOS();
|
||||
const { instance } = useInstance();
|
||||
const { fetchWorkspaceSubscribedPlan, subscribedPlan } = useWorkspaceSubscription();
|
||||
// fetch workspace current plane information
|
||||
useSWR(
|
||||
workspaceSlug && process.env.NEXT_PUBLIC_IS_MULTI_TENANT === "1" ? `WORKSPACE_CURRENT_PLAN_${workspaceSlug}` : null,
|
||||
workspaceSlug && process.env.NEXT_PUBLIC_IS_MULTI_TENANT === "1"
|
||||
? () => fetchWorkspaceSubscribedPlan(workspaceSlug.toString())
|
||||
: null,
|
||||
{
|
||||
errorRetryCount: 2,
|
||||
}
|
||||
);
|
||||
|
||||
const handleProPlanPurchaseModalOpen = () => {
|
||||
setIsProPlanModalOpen(true);
|
||||
captureEvent("pro_plan_modal_opened", {});
|
||||
};
|
||||
|
||||
const handlePlaneOneModalOpen = () => {
|
||||
setIsPlaneOneModalOpen(true);
|
||||
captureEvent("plane_one_modal_opened", {});
|
||||
};
|
||||
|
||||
if (process.env.NEXT_PUBLIC_IS_MULTI_TENANT === "1") {
|
||||
return (
|
||||
<>
|
||||
<CloudProductsModal isOpen={isProPlanModalOpen} handleClose={() => setIsProPlanModalOpen(false)} />
|
||||
<ProPlanDetailsModal isOpen={isProPlanDetailsModalOpen} handleClose={() => setProPlanDetailsModalOpen(false)} />
|
||||
{subscribedPlan === "FREE" && (
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
className="w-full cursor-pointer rounded-2xl px-3 py-1.5 text-center text-sm font-medium outline-none"
|
||||
onClick={handleProPlanPurchaseModalOpen}
|
||||
>
|
||||
Upgrade to Pro
|
||||
</Button>
|
||||
)}
|
||||
{subscribedPlan === "PRO" && (
|
||||
<div className="w-full flex justify-start">
|
||||
<span className="items-center justify-center px-3.5 py-0.5 text-xs leading-4 rounded-xl bg-custom-primary-100/10 text-custom-primary-100">
|
||||
Pro
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (instance?.product === "plane-one") {
|
||||
return (
|
||||
<>
|
||||
<PlaneOneModal isOpen={isPlaneOneModalOpen} handleClose={() => setIsPlaneOneModalOpen(false)} />
|
||||
<Tooltip tooltipContent={`Version: ${instance.current_version}`} isMobile={isMobile}>
|
||||
<button
|
||||
tabIndex={-1}
|
||||
className={cn(
|
||||
getButtonStyling("accent-primary", "md"),
|
||||
"w-fit cursor-pointer rounded-2xl px-3 py-1.5 text-center text-sm font-medium outline-none"
|
||||
)}
|
||||
onClick={handlePlaneOneModalOpen}
|
||||
>
|
||||
<Image src={PlaneOneLogo} alt="Plane One" width={24} height={24} />
|
||||
{"Plane One"}
|
||||
</button>
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip tooltipContent={`Version: v${packageJson.version}`} isMobile={isMobile}>
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from "./use-workspace-page-details";
|
||||
export * from "./use-workspace-pages";
|
||||
export * from "./use-workspace-subscription";
|
||||
|
||||
11
web/ee/hooks/store/use-workspace-subscription.ts
Normal file
11
web/ee/hooks/store/use-workspace-subscription.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { useContext } from "react";
|
||||
// context
|
||||
import { StoreContext } from "@/lib/store-context";
|
||||
// plane web stores
|
||||
import { IWorkspaceSubscriptionStore } from "@/plane-web/store/subscription/subscription.store";
|
||||
|
||||
export const useWorkspaceSubscription = (): IWorkspaceSubscriptionStore => {
|
||||
const context = useContext(StoreContext);
|
||||
if (context === undefined) throw new Error("useWorkspaceSubscription must be used within StoreProvider");
|
||||
return context.workspaceSubscription;
|
||||
};
|
||||
@@ -1,18 +1,25 @@
|
||||
// plane web store
|
||||
import { IWorkspacePageStore, WorkspacePageStore } from "@/plane-web/store/pages/workspace-page.store";
|
||||
// store
|
||||
import {
|
||||
IWorkspaceSubscriptionStore,
|
||||
WorkspaceSubscriptionStore,
|
||||
} from "@/plane-web/store/subscription/subscription.store";
|
||||
import { CoreRootStore } from "@/store/root.store";
|
||||
|
||||
export class RootStore extends CoreRootStore {
|
||||
workspacePages: IWorkspacePageStore;
|
||||
workspaceSubscription: IWorkspaceSubscriptionStore;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.workspacePages = new WorkspacePageStore(this);
|
||||
this.workspaceSubscription = new WorkspaceSubscriptionStore();
|
||||
}
|
||||
|
||||
resetOnSignOut() {
|
||||
super.resetOnSignOut();
|
||||
this.workspacePages = new WorkspacePageStore(this);
|
||||
this.workspaceSubscription = new WorkspaceSubscriptionStore();
|
||||
}
|
||||
}
|
||||
|
||||
38
web/ee/store/subscription/subscription.store.ts
Normal file
38
web/ee/store/subscription/subscription.store.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { action, makeObservable, observable, runInAction } from "mobx";
|
||||
// types
|
||||
import { IWorkspaceProductSubscription } from "@plane/types";
|
||||
// services
|
||||
import { DiscoService } from "@/services/disco.service";
|
||||
|
||||
const discoService = new DiscoService();
|
||||
|
||||
export interface IWorkspaceSubscriptionStore {
|
||||
subscribedPlan: "FREE" | "PRO";
|
||||
fetchWorkspaceSubscribedPlan: (workspaceSlug: string) => Promise<IWorkspaceProductSubscription>;
|
||||
}
|
||||
|
||||
export class WorkspaceSubscriptionStore implements IWorkspaceSubscriptionStore {
|
||||
subscribedPlan: "FREE" | "PRO" = "FREE";
|
||||
|
||||
constructor() {
|
||||
makeObservable(this, {
|
||||
subscribedPlan: observable.ref,
|
||||
fetchWorkspaceSubscribedPlan: action,
|
||||
});
|
||||
}
|
||||
|
||||
fetchWorkspaceSubscribedPlan = async (workspaceSlug: string) => {
|
||||
try {
|
||||
const response = await discoService.getWorkspaceCurrentPlane(workspaceSlug);
|
||||
runInAction(() => {
|
||||
this.subscribedPlan = response.product;
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
runInAction(() => {
|
||||
this.subscribedPlan = "FREE";
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user