From 24fe3689748739538dae89a3d7ad0e671af9e134 Mon Sep 17 00:00:00 2001 From: Steven Date: Sun, 24 Sep 2023 19:44:09 +0800 Subject: [PATCH] feat: implement subscription setting --- frontend/web/src/App.tsx | 36 +--- frontend/web/src/components/DemoBanner.tsx | 8 +- frontend/web/src/components/Header.tsx | 11 +- .../web/src/components/SubscriptionFAQ.tsx | 33 +++ .../components/setting/PreferenceSection.tsx | 29 ++- .../components/setting/WorkspaceSection.tsx | 40 ++-- frontend/web/src/pages/Setting.tsx | 32 --- frontend/web/src/pages/SignIn.tsx | 12 +- frontend/web/src/pages/SignUp.tsx | 10 +- .../web/src/pages/SubscriptionSetting.tsx | 188 ++++++++++++++++++ frontend/web/src/pages/WorkspaceSetting.tsx | 50 +++++ frontend/web/src/routers/index.tsx | 15 +- frontend/web/src/services/index.ts | 3 +- frontend/web/src/services/workspaceService.ts | 21 -- frontend/web/src/stores/index.ts | 2 - frontend/web/src/stores/modules/workspace.ts | 20 -- frontend/web/src/stores/v1/subscription.ts | 11 + frontend/web/src/stores/v1/workspace.ts | 29 +++ 18 files changed, 381 insertions(+), 169 deletions(-) create mode 100644 frontend/web/src/components/SubscriptionFAQ.tsx delete mode 100644 frontend/web/src/pages/Setting.tsx create mode 100644 frontend/web/src/pages/SubscriptionSetting.tsx create mode 100644 frontend/web/src/pages/WorkspaceSetting.tsx delete mode 100644 frontend/web/src/services/workspaceService.ts delete mode 100644 frontend/web/src/stores/modules/workspace.ts create mode 100644 frontend/web/src/stores/v1/subscription.ts create mode 100644 frontend/web/src/stores/v1/workspace.ts diff --git a/frontend/web/src/App.tsx b/frontend/web/src/App.tsx index c35ff00..b7dacbb 100644 --- a/frontend/web/src/App.tsx +++ b/frontend/web/src/App.tsx @@ -2,52 +2,32 @@ import { useColorScheme } from "@mui/joy"; import { useEffect, useState } from "react"; import { Outlet } from "react-router-dom"; import DemoBanner from "./components/DemoBanner"; -import { workspaceServiceClient } from "./grpcweb"; -import { workspaceService } from "./services"; import useUserStore from "./stores/v1/user"; -import { WorkspaceSetting } from "./types/proto/api/v2/workspace_service"; +import useWorkspaceStore from "./stores/v1/workspace"; function App() { const { mode: colorScheme } = useColorScheme(); const userStore = useUserStore(); - const [workspaceSetting, setWorkspaceSetting] = useState(WorkspaceSetting.fromPartial({})); + const workspaceStore = useWorkspaceStore(); const [loading, setLoading] = useState(true); useEffect(() => { - const initialState = async () => { + (async () => { try { - await workspaceService.initialState(); + await Promise.all([workspaceStore.fetchWorkspaceProfile(), workspaceStore.fetchWorkspaceSetting(), userStore.fetchCurrentUser()]); } catch (error) { - // do nothing + // do nth } - - try { - const { setting } = await workspaceServiceClient.getWorkspaceSetting({}); - if (setting) { - setWorkspaceSetting(setting); - } - } catch (error) { - // do nothing - } - - try { - await userStore.fetchCurrentUser(); - } catch (error) { - // do nothing. - } - setLoading(false); - }; - - initialState(); + })(); }, []); useEffect(() => { const styleEl = document.createElement("style"); - styleEl.innerHTML = workspaceSetting.customStyle; + styleEl.innerHTML = workspaceStore.setting.customStyle; styleEl.setAttribute("type", "text/css"); document.body.insertAdjacentElement("beforeend", styleEl); - }, [workspaceSetting.customStyle]); + }, [workspaceStore.setting.customStyle]); useEffect(() => { const root = document.documentElement; diff --git a/frontend/web/src/components/DemoBanner.tsx b/frontend/web/src/components/DemoBanner.tsx index 7e3da47..e4fc956 100644 --- a/frontend/web/src/components/DemoBanner.tsx +++ b/frontend/web/src/components/DemoBanner.tsx @@ -1,11 +1,9 @@ -import { workspaceService } from "../services"; +import useWorkspaceStore from "@/stores/v1/workspace"; import Icon from "./Icon"; const DemoBanner: React.FC = () => { - const { - workspaceProfile: { mode }, - } = workspaceService.getState(); - const shouldShow = mode === "demo"; + const workspaceStore = useWorkspaceStore(); + const shouldShow = workspaceStore.profile.mode === "demo"; if (!shouldShow) return null; diff --git a/frontend/web/src/components/Header.tsx b/frontend/web/src/components/Header.tsx index ec3f60d..15171ae 100644 --- a/frontend/web/src/components/Header.tsx +++ b/frontend/web/src/components/Header.tsx @@ -1,6 +1,8 @@ import { Avatar } from "@mui/joy"; import { useState } from "react"; import { Link } from "react-router-dom"; +import useWorkspaceStore from "@/stores/v1/workspace"; +import { PlanType } from "@/types/proto/api/v2/subscription_service"; import * as api from "../helpers/api"; import useUserStore from "../stores/v1/user"; import AboutDialog from "./AboutDialog"; @@ -8,8 +10,10 @@ import Icon from "./Icon"; import Dropdown from "./common/Dropdown"; const Header: React.FC = () => { + const workspaceStore = useWorkspaceStore(); const currentUser = useUserStore().getCurrentUser(); const [showAboutDialog, setShowAboutDialog] = useState(false); + const profile = workspaceStore.profile; const isAdmin = currentUser.role === "ADMIN"; const handleSignOutButtonClick = async () => { @@ -23,9 +27,14 @@ const Header: React.FC = () => {
- + Slash + {profile.plan === PlanType.PRO && ( + + PRO + + )}
{ + return ( +
+

Frequently Asked Questions

+ + + Can I use the Free plan in my team? + + Of course you can. In the free plan, you can invite up to 5 members to your team. If you need more, you can upgrade to the Pro + plan. + + + + How many devices can the license key be used on? + {`It's unlimited for now, but please don't abuse it.`} + + + {`Can I get a refund if Slash doesn't meet my needs?`} + + Yes, absolutely! You can send a email to me at `stevenlgtm@gmail.com`. I will refund you as soon as possible. + + + +
+ ); +}; + +export default SubscriptionFAQ; diff --git a/frontend/web/src/components/setting/PreferenceSection.tsx b/frontend/web/src/components/setting/PreferenceSection.tsx index 652702c..d3211a7 100644 --- a/frontend/web/src/components/setting/PreferenceSection.tsx +++ b/frontend/web/src/components/setting/PreferenceSection.tsx @@ -62,6 +62,20 @@ const PreferenceSection: React.FC = () => { <>

Preference

+
+
+ Color Theme +
+ +
{releaseGuard() && (
@@ -79,21 +93,6 @@ const PreferenceSection: React.FC = () => {
)} -
-
- Color Theme - -
- -
); diff --git a/frontend/web/src/components/setting/WorkspaceSection.tsx b/frontend/web/src/components/setting/WorkspaceSection.tsx index 1d845cd..8712a2c 100644 --- a/frontend/web/src/components/setting/WorkspaceSection.tsx +++ b/frontend/web/src/components/setting/WorkspaceSection.tsx @@ -1,25 +1,17 @@ import { Button, Checkbox, Textarea } from "@mui/joy"; import { isEqual } from "lodash-es"; -import { useEffect, useRef, useState } from "react"; +import { useRef, useState } from "react"; import toast from "react-hot-toast"; import { workspaceServiceClient } from "@/grpcweb"; -import { releaseGuard } from "@/helpers/utils"; +import useWorkspaceStore from "@/stores/v1/workspace"; import { WorkspaceSetting } from "@/types/proto/api/v2/workspace_service"; const WorkspaceSection: React.FC = () => { - const [workspaceSetting, setWorkspaceSetting] = useState(WorkspaceSetting.fromPartial({})); - const originalWorkspaceSetting = useRef(WorkspaceSetting.fromPartial({})); + const workspaceStore = useWorkspaceStore(); + const [workspaceSetting, setWorkspaceSetting] = useState(workspaceStore.setting); + const originalWorkspaceSetting = useRef(workspaceStore.setting); const allowSave = !isEqual(originalWorkspaceSetting.current, workspaceSetting); - useEffect(() => { - workspaceServiceClient.getWorkspaceSetting({}).then(({ setting }) => { - if (setting) { - setWorkspaceSetting(setting); - originalWorkspaceSetting.current = setting; - } - }); - }, []); - const handleEnableSignUpChange = async (value: boolean) => { setWorkspaceSetting({ ...workspaceSetting, @@ -65,18 +57,16 @@ const WorkspaceSection: React.FC = () => { return (

Workspace settings

- {releaseGuard() && ( -
-

Custom style

-