diff options
| -rw-r--r-- | packages/browser-extension/package.json | 7 | ||||
| -rw-r--r-- | packages/browser-extension/src/App.tsx | 11 | ||||
| -rw-r--r-- | packages/browser-extension/src/OptionsPage.tsx | 6 | ||||
| -rw-r--r-- | packages/browser-extension/src/SavePage.tsx | 83 | ||||
| -rw-r--r-- | packages/browser-extension/src/main.tsx | 5 | ||||
| -rw-r--r-- | packages/browser-extension/src/providers.tsx | 30 | ||||
| -rw-r--r-- | packages/browser-extension/src/utils/providers.tsx | 40 | ||||
| -rw-r--r-- | packages/browser-extension/src/utils/settings.ts (renamed from packages/browser-extension/src/settings.ts) | 0 | ||||
| -rw-r--r-- | packages/browser-extension/src/utils/trpc.ts | 4 | ||||
| -rw-r--r-- | packages/web/package.json | 1 | ||||
| -rw-r--r-- | pnpm-lock.yaml | 90 |
11 files changed, 224 insertions, 53 deletions
diff --git a/packages/browser-extension/package.json b/packages/browser-extension/package.json index 297ba18e..b205a257 100644 --- a/packages/browser-extension/package.json +++ b/packages/browser-extension/package.json @@ -10,12 +10,19 @@ "preview": "vite preview" }, "dependencies": { + "@hoarder/trpc": "0.1.0", + "@tanstack/react-query": "^5.24.8", + "@trpc/client": "11.0.0-next-beta.308", + "@trpc/next": "11.0.0-next-beta.308", + "@trpc/react-query": "11.0.0-next-beta.308", + "@trpc/server": "11.0.0-next-beta.308", "@types/chrome": "^0.0.260", "lucide-react": "^0.330.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.22.0", "use-chrome-storage": "^1.2.2", + "superjson": "^2.2.1", "zod": "^3.22.4" }, "devDependencies": { diff --git a/packages/browser-extension/src/App.tsx b/packages/browser-extension/src/App.tsx index 1044363b..279c8b7a 100644 --- a/packages/browser-extension/src/App.tsx +++ b/packages/browser-extension/src/App.tsx @@ -1,6 +1,6 @@ -import { Settings, X } from "lucide-react"; +import { RefreshCw, Settings, X } from "lucide-react"; import SavePage from "./SavePage"; -import usePluginSettings from "./settings"; +import usePluginSettings from "./utils/settings"; import { useNavigate } from "react-router-dom"; function App() { @@ -18,9 +18,14 @@ function App() { return ( <div className="flex flex-col space-y-2"> - <SavePage settings={settings} /> + <SavePage /> <hr /> <div className="flex justify-end space-x-3"> + {process.env.NODE_ENV == "development" && ( + <button onClick={() => navigate(0)}> + <RefreshCw className="w-4" /> + </button> + )} <button onClick={() => navigate("/options")}> <Settings className="w-4" /> </button> diff --git a/packages/browser-extension/src/OptionsPage.tsx b/packages/browser-extension/src/OptionsPage.tsx index 11a1a76d..5cb4a45b 100644 --- a/packages/browser-extension/src/OptionsPage.tsx +++ b/packages/browser-extension/src/OptionsPage.tsx @@ -1,5 +1,5 @@ import { useRef, useState } from "react"; -import usePluginSettings from "./settings"; +import usePluginSettings from "./utils/settings"; export default function OptionsPage() { const [settings, setSettings, _1, _2, _3] = usePluginSettings(); @@ -38,7 +38,7 @@ export default function OptionsPage() { <label className="m-auto h-full">Server Address</label> <input ref={addressRef} - defaultValue={settings.address || "https://demo.hoarder.app"} + value={settings.address || "https://demo.hoarder.app"} className="h-8 flex-1 rounded-lg border border-gray-300 p-2" /> </div> @@ -46,7 +46,7 @@ export default function OptionsPage() { <label className="m-auto h-full">API Key</label> <input ref={apiKeyRef} - defaultValue={settings.apiKey} + value={settings.apiKey} className="h-8 flex-1 rounded-lg border border-gray-300 p-2" /> </div> diff --git a/packages/browser-extension/src/SavePage.tsx b/packages/browser-extension/src/SavePage.tsx index 955cc7cb..003d4025 100644 --- a/packages/browser-extension/src/SavePage.tsx +++ b/packages/browser-extension/src/SavePage.tsx @@ -1,13 +1,19 @@ import { useEffect, useState } from "react"; -import { Settings } from "./settings"; import Spinner from "./Spinner"; +import { api } from "./utils/trpc"; -export default function SavePage({ settings }: { settings: Settings }) { - const [loading, setLoading] = useState(true); +export default function SavePage() { const [error, setError] = useState<string | undefined>(undefined); + const { mutate: createBookmark, status } = + api.bookmarks.createBookmark.useMutation({ + onError: (e) => { + setError("Something went wrong: " + e.message); + }, + }); + useEffect(() => { - async function runFetch() { + async function runSave() { let currentUrl; const [currentTab] = await chrome.tabs.query({ active: true, @@ -17,52 +23,37 @@ export default function SavePage({ settings }: { settings: Settings }) { currentUrl = currentTab.url; } else { setError("Couldn't find the URL of the current tab"); - setLoading(false); return; } - try { - const resp = await fetch( - `${settings.address}/api/trpc/bookmarks.createBookmark`, - { - method: "POST", - headers: { - Authorization: `Bearer ${settings.apiKey}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ - json: { - type: "link", - url: currentUrl, - }, - }), - }, - ); - if (!resp.ok) { - setError( - "Something went wrong: " + JSON.stringify(await resp.json()), - ); - } - } catch (e) { - setError("Message: " + (e as Error).message); - } - - setLoading(false); + createBookmark({ + type: "link", + url: currentUrl, + }); } - runFetch(); - }, [settings]); - - if (loading) { - return ( - <div className="m-auto"> - <Spinner /> - </div> - ); - } + runSave(); + }, [createBookmark]); - if (error) { - return <div className="text-red-500">{error} ...</div>; + switch (status) { + case "error": { + return <div className="text-red-500">{error}</div>; + } + case "success": { + return <div className="m-auto text-lg">Bookmark Saved</div>; + } + case "pending": { + return ( + <div className="m-auto"> + <Spinner /> + </div> + ); + } + case "idle": { + return ( + <div className="m-auto"> + <Spinner /> + </div> + ); + } } - - return <div className="m-auto text-lg">Bookmark Saved</div>; } diff --git a/packages/browser-extension/src/main.tsx b/packages/browser-extension/src/main.tsx index c4f5a2d9..3e269982 100644 --- a/packages/browser-extension/src/main.tsx +++ b/packages/browser-extension/src/main.tsx @@ -5,6 +5,7 @@ import "./index.css"; import { createHashRouter, RouterProvider } from "react-router-dom"; import OptionsPage from "./OptionsPage.tsx"; import NotConfiguredPage from "./NotConfiguredPage.tsx"; +import { Providers } from "./utils/providers.tsx"; const router = createHashRouter([ { @@ -24,7 +25,9 @@ const router = createHashRouter([ ReactDOM.createRoot(document.getElementById("root")!).render( <React.StrictMode> <div className="w-96 p-4"> - <RouterProvider router={router} /> + <Providers> + <RouterProvider router={router} /> + </Providers> </div> </React.StrictMode>, ); diff --git a/packages/browser-extension/src/providers.tsx b/packages/browser-extension/src/providers.tsx new file mode 100644 index 00000000..a055f3d1 --- /dev/null +++ b/packages/browser-extension/src/providers.tsx @@ -0,0 +1,30 @@ +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { httpBatchLink } from "@trpc/client"; +import React, { useState } from "react"; +import { trpc } from "./trpc"; + +export function App() { + const [queryClient] = useState(() => new QueryClient()); + const [trpcClient] = useState(() => + trpc.createClient({ + links: [ + httpBatchLink({ + url: "http://localhost:3000/trpc", + // You can pass any HTTP headers you wish here + async headers() { + return { + // authorization: getAuthCookie(), + }; + }, + }), + ], + }), + ); + return ( + <trpc.Provider client={trpcClient} queryClient={queryClient}> + <QueryClientProvider client={queryClient}> + {/* Your app here */} + </QueryClientProvider> + </trpc.Provider> + ); +} diff --git a/packages/browser-extension/src/utils/providers.tsx b/packages/browser-extension/src/utils/providers.tsx new file mode 100644 index 00000000..c11331f0 --- /dev/null +++ b/packages/browser-extension/src/utils/providers.tsx @@ -0,0 +1,40 @@ +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { httpBatchLink } from "@trpc/client"; +import { useCallback, useEffect, useState } from "react"; +import { api } from "./trpc"; +import usePluginSettings from "./settings"; +import superjson from "superjson"; + +export function Providers({ children }: { children: React.ReactNode }) { + const [settings] = usePluginSettings(); + const [queryClient] = useState(() => new QueryClient()); + + const getTrpcClient = useCallback(() => { + console.log(settings); + return api.createClient({ + links: [ + httpBatchLink({ + url: `${settings.address}/api/trpc`, + async headers() { + return { + Authorization: `Bearer ${settings.apiKey}`, + }; + }, + transformer: superjson, + }), + ], + }); + }, [settings]); + + const [trpcClient, setTrpcClient] = useState(getTrpcClient()); + + useEffect(() => { + setTrpcClient(getTrpcClient()); + }, [getTrpcClient]); + + return ( + <api.Provider client={trpcClient} queryClient={queryClient}> + <QueryClientProvider client={queryClient}>{children}</QueryClientProvider> + </api.Provider> + ); +} diff --git a/packages/browser-extension/src/settings.ts b/packages/browser-extension/src/utils/settings.ts index ee7f0722..ee7f0722 100644 --- a/packages/browser-extension/src/settings.ts +++ b/packages/browser-extension/src/utils/settings.ts diff --git a/packages/browser-extension/src/utils/trpc.ts b/packages/browser-extension/src/utils/trpc.ts new file mode 100644 index 00000000..da21a55a --- /dev/null +++ b/packages/browser-extension/src/utils/trpc.ts @@ -0,0 +1,4 @@ +import { createTRPCReact } from "@trpc/react-query"; +import type { AppRouter } from "@hoarder/trpc/routers/_app"; + +export const api = createTRPCReact<AppRouter>(); diff --git a/packages/web/package.json b/packages/web/package.json index e0c9d407..e8dfcbe1 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -36,6 +36,7 @@ "@trpc/next": "11.0.0-next-beta.304", "@trpc/react-query": "^11.0.0-next-beta.304", "@trpc/server": "11.0.0-next-beta.304", + "bcrypt": "^5.1.1", "better-sqlite3": "^9.4.3", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dc333de5..caf3f970 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -69,6 +69,24 @@ importers: packages/browser-extension: dependencies: + '@hoarder/trpc': + specifier: 0.1.0 + version: link:../trpc + '@tanstack/react-query': + specifier: ^5.24.8 + version: 5.24.8(react@18.2.0) + '@trpc/client': + specifier: 11.0.0-next-beta.308 + version: 11.0.0-next-beta.308(@trpc/server@11.0.0-next-beta.308) + '@trpc/next': + specifier: 11.0.0-next-beta.308 + version: 11.0.0-next-beta.308(@tanstack/react-query@5.24.8)(@trpc/client@11.0.0-next-beta.308)(@trpc/react-query@11.0.0-next-beta.308)(@trpc/server@11.0.0-next-beta.308)(next@14.1.1)(react-dom@18.2.0)(react@18.2.0) + '@trpc/react-query': + specifier: 11.0.0-next-beta.308 + version: 11.0.0-next-beta.308(@tanstack/react-query@5.24.8)(@trpc/client@11.0.0-next-beta.308)(@trpc/server@11.0.0-next-beta.308)(react-dom@18.2.0)(react@18.2.0) + '@trpc/server': + specifier: 11.0.0-next-beta.308 + version: 11.0.0-next-beta.308 '@types/chrome': specifier: ^0.0.260 version: 0.0.260 @@ -84,6 +102,9 @@ importers: react-router-dom: specifier: ^6.22.0 version: 6.22.1(react-dom@18.2.0)(react@18.2.0) + superjson: + specifier: ^2.2.1 + version: 2.2.1 use-chrome-storage: specifier: ^1.2.2 version: 1.3.0(react@18.2.0) @@ -297,6 +318,9 @@ importers: '@trpc/server': specifier: 11.0.0-next-beta.304 version: 11.0.0-next-beta.304 + bcrypt: + specifier: ^5.1.1 + version: 5.1.1 better-sqlite3: specifier: ^9.4.3 version: 9.4.3 @@ -3836,6 +3860,10 @@ packages: resolution: {integrity: sha512-xYhxiMUPh1JzamVK8VwwkBpIBXVYRyIBW9gjSN+/BB4kL1nS86gnRWeW8L+sacCj1RiyEsysJe3GSvtbIpHdWw==} dev: false + /@tanstack/query-core@5.24.8: + resolution: {integrity: sha512-yH7KnfXMf10p1U5GffTQzFi2Miiw6WJZImGYGdV7eqa5ZbKO8qVx9lOA9SfhIaJXomrMp1Yz5w/CBhVM3yWeTA==} + dev: false + /@tanstack/query-devtools@5.24.0: resolution: {integrity: sha512-pThim455t69zrZaQKa7IRkEIK8UBTS+gHVAdNfhO72Xh4rWpMc63ovRje5/n6iw63+d6QiJzVadsJVdPoodSeQ==} dev: false @@ -3860,6 +3888,15 @@ packages: react: 18.2.0 dev: false + /@tanstack/react-query@5.24.8(react@18.2.0): + resolution: {integrity: sha512-jB3JS9SzDmBySk9VVOTPt/0ixWEb3K3dy9IExlVl/1NouY3N7HzAqG/1d4m6E9eFfKJoLvA/hBksaLu0lw627A==} + peerDependencies: + react: ^18.0.0 + dependencies: + '@tanstack/query-core': 5.24.8 + react: 18.2.0 + dev: false + /@tootallnate/quickjs-emscripten@0.23.0: resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} dev: false @@ -3872,6 +3909,14 @@ packages: '@trpc/server': 11.0.0-next-beta.304 dev: false + /@trpc/client@11.0.0-next-beta.308(@trpc/server@11.0.0-next-beta.308): + resolution: {integrity: sha512-bg8EV6qVZZl6/v9HhfmntEbPcjtzi3MFhdHUv9l24HLkLAJPvBCMMsjjFZG6PX+jwyXTFjSBGzaXwpnNtdE1tQ==} + peerDependencies: + '@trpc/server': 11.0.0-next-beta.308+955edd79a + dependencies: + '@trpc/server': 11.0.0-next-beta.308 + dev: false + /@trpc/next@11.0.0-next-beta.304(@tanstack/react-query@5.24.6)(@trpc/client@11.0.0-next-beta.304)(@trpc/react-query@11.0.0-next-beta.304)(@trpc/server@11.0.0-next-beta.304)(next@14.1.1)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-bCCnkzqEpl6Z3R11fzPHxNxdgvoCZ2yDWxQZQlFPANSJVihjzLCMCK60AjXawDXdVUEqbA/OXP6htZeozjmWZg==} peerDependencies: @@ -3897,6 +3942,31 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@trpc/next@11.0.0-next-beta.308(@tanstack/react-query@5.24.8)(@trpc/client@11.0.0-next-beta.308)(@trpc/react-query@11.0.0-next-beta.308)(@trpc/server@11.0.0-next-beta.308)(next@14.1.1)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-zur2BkpI4NzKlg5P0RxGwk9yzYMuaKlXrS4vgwEsnr8CrVTqgClnStLsQOD14gwWRilp5QaJcFiPE2607OzQAg==} + peerDependencies: + '@tanstack/react-query': ^5.0.0 + '@trpc/client': 11.0.0-next-beta.308+955edd79a + '@trpc/react-query': 11.0.0-next-beta.308+955edd79a + '@trpc/server': 11.0.0-next-beta.308+955edd79a + next: '*' + react: '>=16.8.0' + react-dom: '>=16.8.0' + peerDependenciesMeta: + '@tanstack/react-query': + optional: true + '@trpc/react-query': + optional: true + dependencies: + '@tanstack/react-query': 5.24.8(react@18.2.0) + '@trpc/client': 11.0.0-next-beta.308(@trpc/server@11.0.0-next-beta.308) + '@trpc/react-query': 11.0.0-next-beta.308(@tanstack/react-query@5.24.8)(@trpc/client@11.0.0-next-beta.308)(@trpc/server@11.0.0-next-beta.308)(react-dom@18.2.0)(react@18.2.0) + '@trpc/server': 11.0.0-next-beta.308 + next: 14.1.1(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@trpc/react-query@11.0.0-next-beta.304(@tanstack/react-query@5.24.6)(@trpc/client@11.0.0-next-beta.304)(@trpc/server@11.0.0-next-beta.304)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-DkfNUVxxEgKtel5Z9DUaw815oy8VGK7i626FrUs7PRQ7PEcQ5WDBXbYXsukOqx+qEpx09dgiWBBG6LGQf6U9Dg==} peerDependencies: @@ -3913,10 +3983,30 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@trpc/react-query@11.0.0-next-beta.308(@tanstack/react-query@5.24.8)(@trpc/client@11.0.0-next-beta.308)(@trpc/server@11.0.0-next-beta.308)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-+0g42nW0zOXfpRN90aMuhPZ/BvwQu4IOiWP5xByRq2E+EWrWxJAFdxgS4xpKR49KlM+vKLSgkqj5yeYXyd82hw==} + peerDependencies: + '@tanstack/react-query': ^5.0.0 + '@trpc/client': 11.0.0-next-beta.308+955edd79a + '@trpc/server': 11.0.0-next-beta.308+955edd79a + react: '>=18.2.0' + react-dom: '>=18.2.0' + dependencies: + '@tanstack/react-query': 5.24.8(react@18.2.0) + '@trpc/client': 11.0.0-next-beta.308(@trpc/server@11.0.0-next-beta.308) + '@trpc/server': 11.0.0-next-beta.308 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@trpc/server@11.0.0-next-beta.304: resolution: {integrity: sha512-vviyE80LZ8LFML/w0usDjcUbduhsBtLBO+MKXhAtRfo25FxajhDFWvuvdqglAlTxFmCuH7oX+GxfCTjcsnnHyQ==} dev: false + /@trpc/server@11.0.0-next-beta.308: + resolution: {integrity: sha512-GdYgcbecAafHQszqMVeHrX45c0hhAISvB+w9Ja40nZcb4kgaNvhflSVIn8XbHKUG8urmYI9kTL2k8hD/59/LMA==} + dev: false + /@tsconfig/node10@1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} |
