diff --git a/frontend/extension/src/components/CreateShortcutButton.tsx b/frontend/extension/src/components/CreateShortcutButton.tsx index 3657444..87a5e69 100644 --- a/frontend/extension/src/components/CreateShortcutButton.tsx +++ b/frontend/extension/src/components/CreateShortcutButton.tsx @@ -1,8 +1,9 @@ import { Button, IconButton, Input, Modal, ModalDialog } from "@mui/joy"; -import { useStorage } from "@plasmohq/storage/hook"; import { useEffect, useState } from "react"; import { toast } from "react-hot-toast"; +import { useStorageContext } from "@/context"; import useShortcutStore from "@/store/shortcut"; +import type { Visibility } from "@/types/proto/api/v1/common"; import { Shortcut } from "@/types/proto/api/v1/shortcut_service"; import Icon from "./Icon"; @@ -13,8 +14,7 @@ interface State { } const CreateShortcutButton = () => { - const [instanceUrl] = useStorage("domain"); - const [accessToken] = useStorage("access_token"); + const context = useStorageContext(); const shortcutStore = useShortcutStore(); const [state, setState] = useState({ name: "", @@ -101,13 +101,14 @@ const CreateShortcutButton = () => { try { const tags = tag.split(" ").filter(Boolean); await shortcutStore.createShortcut( - instanceUrl, - accessToken, + context.instanceUrl, + context.accessToken, Shortcut.fromPartial({ name: state.name, title: state.title, link: state.link, tags, + visibility: context.defaultVisibility as Visibility, }) ); toast.success("Shortcut created successfully"); diff --git a/frontend/extension/src/components/PullShortcutsButton.tsx b/frontend/extension/src/components/PullShortcutsButton.tsx index c00f11b..2d923c7 100644 --- a/frontend/extension/src/components/PullShortcutsButton.tsx +++ b/frontend/extension/src/components/PullShortcutsButton.tsx @@ -1,24 +1,23 @@ import { IconButton } from "@mui/joy"; -import { useStorage } from "@plasmohq/storage/hook"; import { useEffect } from "react"; import { toast } from "react-hot-toast"; +import { useStorageContext } from "@/context"; import useShortcutStore from "@/store/shortcut"; import Icon from "./Icon"; const PullShortcutsButton = () => { - const [instanceUrl] = useStorage("domain"); - const [accessToken] = useStorage("access_token"); + const context = useStorageContext(); const shortcutStore = useShortcutStore(); useEffect(() => { - if (instanceUrl && accessToken) { + if (context.instanceUrl && context.accessToken) { handlePullShortcuts(true); } - }, [instanceUrl, accessToken]); + }, [context]); const handlePullShortcuts = async (silence = false) => { try { - await shortcutStore.fetchShortcutList(instanceUrl, accessToken); + await shortcutStore.fetchShortcutList(context.instanceUrl, context.accessToken); if (!silence) { toast.success("Shortcuts pulled"); } diff --git a/frontend/extension/src/context/context.ts b/frontend/extension/src/context/context.ts new file mode 100644 index 0000000..7f92cf2 --- /dev/null +++ b/frontend/extension/src/context/context.ts @@ -0,0 +1,27 @@ +import { createContext, useContext } from "react"; +import { Visibility } from "@/types/proto/api/v1/common"; + +interface Context { + instanceUrl?: string; + accessToken?: string; + defaultVisibility: string; + setInstanceUrl: (instanceUrl: string) => void; + setAccessToken: (accessToken: string) => void; + setDefaultVisibility: (visibility: string) => void; +} + +export const StorageContext = createContext({ + instanceUrl: undefined, + accessToken: undefined, + defaultVisibility: Visibility.PRIVATE, + setInstanceUrl: () => {}, + setAccessToken: () => {}, + setDefaultVisibility: () => {}, +}); + +const useStorageContext = () => { + const context = useContext(StorageContext); + return context; +}; + +export default useStorageContext; diff --git a/frontend/extension/src/context/index.ts b/frontend/extension/src/context/index.ts new file mode 100644 index 0000000..1825171 --- /dev/null +++ b/frontend/extension/src/context/index.ts @@ -0,0 +1,4 @@ +import useStorageContext from "./context"; +import StorageContextProvider from "./provider"; + +export { useStorageContext, StorageContextProvider }; diff --git a/frontend/extension/src/context/provider.tsx b/frontend/extension/src/context/provider.tsx new file mode 100644 index 0000000..77fca1f --- /dev/null +++ b/frontend/extension/src/context/provider.tsx @@ -0,0 +1,58 @@ +import { Storage } from "@plasmohq/storage"; +import { useEffect, useState } from "react"; +import { Visibility } from "@/types/proto/api/v1/common"; +import { StorageContext } from "./context"; + +interface Props { + children: React.ReactNode; +} + +const StorageContextProvider = ({ children }: Props) => { + const storage = new Storage(); + const [instanceUrl, setInstanceUrl] = useState(undefined); + const [accessToken, setAccessToken] = useState(undefined); + const [defaultVisibility, setDefaultVisibility] = useState(Visibility.PRIVATE); + const [isInitialized, setIsInitialized] = useState(false); + + useEffect(() => { + (async () => { + const domain = await storage.get("domain"); + const accessToken = await storage.get("access_token"); + const defaultVisibility = (await storage.get("default_visibility")) as Visibility; + + setInstanceUrl(domain); + setAccessToken(accessToken); + setDefaultVisibility(defaultVisibility); + setIsInitialized(true); + })(); + + storage.watch({ + domain: (c) => { + setInstanceUrl(c.newValue); + }, + access_token: (c) => { + setAccessToken(c.newValue); + }, + default_visibility: (c) => { + setDefaultVisibility(c.newValue as Visibility); + }, + }); + }, []); + + return ( + storage.set("domain", instanceUrl), + setAccessToken: (accessToken: string) => storage.set("access_token", accessToken), + setDefaultVisibility: (visibility: Visibility) => storage.set("default_visibility", visibility), + }} + > + {isInitialized && children} + + ); +}; + +export default StorageContextProvider; diff --git a/frontend/extension/src/options.tsx b/frontend/extension/src/options.tsx index cffc5a4..5bb0344 100644 --- a/frontend/extension/src/options.tsx +++ b/frontend/extension/src/options.tsx @@ -1,14 +1,15 @@ import { Button, CssVarsProvider, Divider, Input, Select, Option } from "@mui/joy"; -import { useStorage } from "@plasmohq/storage/hook"; import { useEffect, useState } from "react"; import { Toaster, toast } from "react-hot-toast"; import Icon from "./components/Icon"; import Logo from "./components/Logo"; import PullShortcutsButton from "./components/PullShortcutsButton"; import ShortcutsContainer from "./components/ShortcutsContainer"; +import { StorageContextProvider, useStorageContext } from "./context"; import useColorTheme from "./hooks/useColorTheme"; import useShortcutStore from "./store/shortcut"; import "./style.css"; +import { Visibility } from "./types/proto/api/v1/common"; interface SettingState { domain: string; @@ -32,22 +33,21 @@ const colorThemeOptions = [ const IndexOptions = () => { const { colorTheme, setColorTheme } = useColorTheme(); - const [domain, setDomain] = useStorage("domain", (v) => (v ? v : "")); - const [accessToken, setAccessToken] = useStorage("access_token", (v) => (v ? v : "")); + const context = useStorageContext(); const [settingState, setSettingState] = useState({ - domain, - accessToken, + domain: context.instanceUrl || "", + accessToken: context.accessToken || "", }); const shortcutStore = useShortcutStore(); const shortcuts = shortcutStore.getShortcutList(); - const isInitialized = domain && accessToken; + const isInitialized = context.instanceUrl && context.accessToken; useEffect(() => { setSettingState({ - domain, - accessToken, + domain: context.instanceUrl || "", + accessToken: context.accessToken || "", }); - }, [domain, accessToken]); + }, [context]); const setPartialSettingState = (partialSettingState: Partial) => { setSettingState((prevState) => ({ @@ -57,8 +57,8 @@ const IndexOptions = () => { }; const handleSaveSetting = () => { - setDomain(settingState.domain); - setAccessToken(settingState.accessToken); + context.setInstanceUrl(settingState.domain); + context.setAccessToken(settingState.accessToken); toast.success("Setting saved"); }; @@ -66,6 +66,10 @@ const IndexOptions = () => { setColorTheme(colorTheme as any); }; + const handleDefaultVisibilitySelect = (value: Visibility) => { + context.setDefaultVisibility(value); + }; + return (
@@ -92,10 +96,10 @@ const IndexOptions = () => {
Instance URL - {domain !== "" && ( + {context.instanceUrl !== "" && ( Go to my Slash @@ -133,9 +137,9 @@ const IndexOptions = () => { -

Preference

+

Preference

-
+
Color Theme
@@ -149,6 +153,17 @@ const IndexOptions = () => { })}
+ +
+
+ Default Visibility +
+ +
{isInitialized && ( @@ -170,10 +185,12 @@ const IndexOptions = () => { const Options = () => { return ( - - - - + + + + + + ); }; diff --git a/frontend/extension/src/popup.tsx b/frontend/extension/src/popup.tsx index 9e02b26..4be21e4 100644 --- a/frontend/extension/src/popup.tsx +++ b/frontend/extension/src/popup.tsx @@ -1,5 +1,4 @@ import { Button, CssVarsProvider, Divider, IconButton } from "@mui/joy"; -import { useStorage } from "@plasmohq/storage/hook"; import { useEffect } from "react"; import { Toaster } from "react-hot-toast"; import CreateShortcutButton from "@/components/CreateShortcutButton"; @@ -7,24 +6,24 @@ import Icon from "@/components/Icon"; import Logo from "@/components/Logo"; import PullShortcutsButton from "@/components/PullShortcutsButton"; import ShortcutsContainer from "@/components/ShortcutsContainer"; +import { StorageContextProvider, useStorageContext } from "./context"; import useColorTheme from "./hooks/useColorTheme"; import useShortcutStore from "./store/shortcut"; import "./style.css"; const IndexPopup = () => { useColorTheme(); - const [instanceUrl] = useStorage("domain", ""); - const [accessToken] = useStorage("access_token", ""); + const context = useStorageContext(); const shortcutStore = useShortcutStore(); const shortcuts = shortcutStore.getShortcutList(); - const isInitialized = instanceUrl && accessToken; + const isInitialized = context.instanceUrl && context.accessToken; useEffect(() => { if (!isInitialized) { return; } - shortcutStore.fetchShortcutList(instanceUrl, accessToken); + shortcutStore.fetchShortcutList(context.instanceUrl, context.accessToken); }, [isInitialized]); const handleSettingButtonClick = () => { @@ -86,7 +85,7 @@ const IndexPopup = () => {