From 04572a8e5081b1e4871e273cde9dbaaa44c52fe0 Mon Sep 17 00:00:00 2001 From: MohamedBassem Date: Wed, 13 Mar 2024 21:43:44 +0000 Subject: structure: Create apps dir and copy tooling dir from t3-turbo repo --- packages/web/README.md | 36 ---- packages/web/app/api/auth/[...nextauth]/route.tsx | 3 - packages/web/app/api/trpc/[trpc]/route.ts | 36 ---- packages/web/app/dashboard/admin/page.tsx | 203 ------------------- packages/web/app/dashboard/archive/page.tsx | 9 - packages/web/app/dashboard/bookmarks/layout.tsx | 23 --- packages/web/app/dashboard/bookmarks/loading.tsx | 11 - packages/web/app/dashboard/bookmarks/page.tsx | 5 - packages/web/app/dashboard/error.tsx | 9 - packages/web/app/dashboard/favourites/page.tsx | 14 -- packages/web/app/dashboard/layout.tsx | 24 --- packages/web/app/dashboard/lists/[listId]/page.tsx | 44 ---- packages/web/app/dashboard/lists/page.tsx | 14 -- packages/web/app/dashboard/not-found.tsx | 7 - .../app/dashboard/preview/[bookmarkId]/page.tsx | 14 -- packages/web/app/dashboard/search/page.tsx | 41 ---- packages/web/app/dashboard/settings/page.tsx | 9 - packages/web/app/dashboard/tags/[tagName]/page.tsx | 55 ----- packages/web/app/dashboard/tags/page.tsx | 56 ------ packages/web/app/favicon.ico | Bin 15406 -> 0 bytes packages/web/app/globals.css | 76 ------- packages/web/app/layout.tsx | 51 ----- packages/web/app/page.tsx | 12 -- packages/web/app/signin/page.tsx | 25 --- packages/web/components.json | 17 -- .../dashboard/bookmarks/AddLinkButton.tsx | 102 ---------- .../dashboard/bookmarks/AddToListModal.tsx | 168 ---------------- .../dashboard/bookmarks/BookmarkCardSkeleton.tsx | 30 --- .../dashboard/bookmarks/BookmarkOptions.tsx | 185 ----------------- .../dashboard/bookmarks/BookmarkPreview.tsx | 101 ---------- .../dashboard/bookmarks/BookmarkedTextEditor.tsx | 109 ---------- .../dashboard/bookmarks/BookmarkedTextViewer.tsx | 20 -- .../components/dashboard/bookmarks/Bookmarks.tsx | 32 --- .../dashboard/bookmarks/BookmarksGrid.tsx | 64 ------ .../components/dashboard/bookmarks/LinkCard.tsx | 114 ----------- .../web/components/dashboard/bookmarks/TagList.tsx | 39 ---- .../components/dashboard/bookmarks/TagModal.tsx | 207 ------------------- .../components/dashboard/bookmarks/TextCard.tsx | 94 --------- .../web/components/dashboard/bookmarks/TopNav.tsx | 43 ---- .../components/dashboard/lists/AllListsView.tsx | 66 ------ .../dashboard/lists/DeleteListButton.tsx | 77 ------- .../web/components/dashboard/lists/ListView.tsx | 25 --- .../components/dashboard/search/SearchInput.tsx | 25 --- .../components/dashboard/settings/AddApiKey.tsx | 167 ---------------- .../dashboard/settings/ApiKeySettings.tsx | 49 ----- .../components/dashboard/settings/DeleteApiKey.tsx | 74 ------- .../web/components/dashboard/sidebar/AllLists.tsx | 60 ------ .../components/dashboard/sidebar/ModileSidebar.tsx | 24 --- .../dashboard/sidebar/ModileSidebarItem.tsx | 27 --- .../components/dashboard/sidebar/NewListModal.tsx | 170 ---------------- .../web/components/dashboard/sidebar/Sidebar.tsx | 66 ------ .../components/dashboard/sidebar/SidebarItem.tsx | 33 --- .../dashboard/sidebar/SidebarProfileOptions.tsx | 35 ---- packages/web/components/signin/CredentialsForm.tsx | 222 --------------------- packages/web/components/signin/SignInForm.tsx | 37 ---- .../web/components/signin/SignInProviderButton.tsx | 21 -- packages/web/components/ui/action-button.tsx | 25 --- packages/web/components/ui/back-button.tsx | 9 - packages/web/components/ui/badge.tsx | 36 ---- packages/web/components/ui/button.tsx | 56 ------ packages/web/components/ui/card.tsx | 86 -------- packages/web/components/ui/dialog.tsx | 122 ----------- packages/web/components/ui/dropdown-menu.tsx | 200 ------------------- packages/web/components/ui/form.tsx | 177 ---------------- packages/web/components/ui/imageCard.tsx | 70 ------- packages/web/components/ui/input.tsx | 25 --- packages/web/components/ui/label.tsx | 26 --- packages/web/components/ui/popover.tsx | 31 --- packages/web/components/ui/scroll-area.tsx | 48 ----- packages/web/components/ui/select.tsx | 160 --------------- packages/web/components/ui/separator.tsx | 31 --- packages/web/components/ui/skeleton.tsx | 15 -- packages/web/components/ui/spinner.tsx | 20 -- packages/web/components/ui/table.tsx | 117 ----------- packages/web/components/ui/tabs.tsx | 55 ----- packages/web/components/ui/textarea.tsx | 24 --- packages/web/components/ui/toast.tsx | 127 ------------ packages/web/components/ui/toaster.tsx | 35 ---- packages/web/components/ui/use-toast.ts | 189 ------------------ packages/web/lib/bookmarkUtils.tsx | 22 -- packages/web/lib/hooks/bookmark-search.ts | 73 ------- packages/web/lib/providers.tsx | 75 ------- packages/web/lib/trpc.tsx | 5 - packages/web/lib/utils.ts | 6 - packages/web/next.config.mjs | 43 ---- packages/web/package.json | 74 ------- packages/web/postcss.config.js | 6 - packages/web/public/blur.avif | Bin 52746 -> 0 bytes packages/web/public/icons/logo-128.png | Bin 2362 -> 0 bytes packages/web/public/icons/logo-16.png | Bin 287 -> 0 bytes packages/web/public/icons/logo-48.png | Bin 780 -> 0 bytes packages/web/public/manifest.json | 25 --- packages/web/server/api/client.ts | 16 -- packages/web/server/auth.ts | 96 --------- packages/web/tailwind.config.ts | 89 --------- packages/web/tsconfig.json | 28 --- packages/web/vitest.config.ts | 14 -- 97 files changed, 5536 deletions(-) delete mode 100644 packages/web/README.md delete mode 100644 packages/web/app/api/auth/[...nextauth]/route.tsx delete mode 100644 packages/web/app/api/trpc/[trpc]/route.ts delete mode 100644 packages/web/app/dashboard/admin/page.tsx delete mode 100644 packages/web/app/dashboard/archive/page.tsx delete mode 100644 packages/web/app/dashboard/bookmarks/layout.tsx delete mode 100644 packages/web/app/dashboard/bookmarks/loading.tsx delete mode 100644 packages/web/app/dashboard/bookmarks/page.tsx delete mode 100644 packages/web/app/dashboard/error.tsx delete mode 100644 packages/web/app/dashboard/favourites/page.tsx delete mode 100644 packages/web/app/dashboard/layout.tsx delete mode 100644 packages/web/app/dashboard/lists/[listId]/page.tsx delete mode 100644 packages/web/app/dashboard/lists/page.tsx delete mode 100644 packages/web/app/dashboard/not-found.tsx delete mode 100644 packages/web/app/dashboard/preview/[bookmarkId]/page.tsx delete mode 100644 packages/web/app/dashboard/search/page.tsx delete mode 100644 packages/web/app/dashboard/settings/page.tsx delete mode 100644 packages/web/app/dashboard/tags/[tagName]/page.tsx delete mode 100644 packages/web/app/dashboard/tags/page.tsx delete mode 100644 packages/web/app/favicon.ico delete mode 100644 packages/web/app/globals.css delete mode 100644 packages/web/app/layout.tsx delete mode 100644 packages/web/app/page.tsx delete mode 100644 packages/web/app/signin/page.tsx delete mode 100644 packages/web/components.json delete mode 100644 packages/web/components/dashboard/bookmarks/AddLinkButton.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/AddToListModal.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/BookmarkCardSkeleton.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/BookmarkOptions.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/BookmarkPreview.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/BookmarkedTextViewer.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/Bookmarks.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/BookmarksGrid.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/LinkCard.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/TagList.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/TagModal.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/TextCard.tsx delete mode 100644 packages/web/components/dashboard/bookmarks/TopNav.tsx delete mode 100644 packages/web/components/dashboard/lists/AllListsView.tsx delete mode 100644 packages/web/components/dashboard/lists/DeleteListButton.tsx delete mode 100644 packages/web/components/dashboard/lists/ListView.tsx delete mode 100644 packages/web/components/dashboard/search/SearchInput.tsx delete mode 100644 packages/web/components/dashboard/settings/AddApiKey.tsx delete mode 100644 packages/web/components/dashboard/settings/ApiKeySettings.tsx delete mode 100644 packages/web/components/dashboard/settings/DeleteApiKey.tsx delete mode 100644 packages/web/components/dashboard/sidebar/AllLists.tsx delete mode 100644 packages/web/components/dashboard/sidebar/ModileSidebar.tsx delete mode 100644 packages/web/components/dashboard/sidebar/ModileSidebarItem.tsx delete mode 100644 packages/web/components/dashboard/sidebar/NewListModal.tsx delete mode 100644 packages/web/components/dashboard/sidebar/Sidebar.tsx delete mode 100644 packages/web/components/dashboard/sidebar/SidebarItem.tsx delete mode 100644 packages/web/components/dashboard/sidebar/SidebarProfileOptions.tsx delete mode 100644 packages/web/components/signin/CredentialsForm.tsx delete mode 100644 packages/web/components/signin/SignInForm.tsx delete mode 100644 packages/web/components/signin/SignInProviderButton.tsx delete mode 100644 packages/web/components/ui/action-button.tsx delete mode 100644 packages/web/components/ui/back-button.tsx delete mode 100644 packages/web/components/ui/badge.tsx delete mode 100644 packages/web/components/ui/button.tsx delete mode 100644 packages/web/components/ui/card.tsx delete mode 100644 packages/web/components/ui/dialog.tsx delete mode 100644 packages/web/components/ui/dropdown-menu.tsx delete mode 100644 packages/web/components/ui/form.tsx delete mode 100644 packages/web/components/ui/imageCard.tsx delete mode 100644 packages/web/components/ui/input.tsx delete mode 100644 packages/web/components/ui/label.tsx delete mode 100644 packages/web/components/ui/popover.tsx delete mode 100644 packages/web/components/ui/scroll-area.tsx delete mode 100644 packages/web/components/ui/select.tsx delete mode 100644 packages/web/components/ui/separator.tsx delete mode 100644 packages/web/components/ui/skeleton.tsx delete mode 100644 packages/web/components/ui/spinner.tsx delete mode 100644 packages/web/components/ui/table.tsx delete mode 100644 packages/web/components/ui/tabs.tsx delete mode 100644 packages/web/components/ui/textarea.tsx delete mode 100644 packages/web/components/ui/toast.tsx delete mode 100644 packages/web/components/ui/toaster.tsx delete mode 100644 packages/web/components/ui/use-toast.ts delete mode 100644 packages/web/lib/bookmarkUtils.tsx delete mode 100644 packages/web/lib/hooks/bookmark-search.ts delete mode 100644 packages/web/lib/providers.tsx delete mode 100644 packages/web/lib/trpc.tsx delete mode 100644 packages/web/lib/utils.ts delete mode 100644 packages/web/next.config.mjs delete mode 100644 packages/web/package.json delete mode 100644 packages/web/postcss.config.js delete mode 100644 packages/web/public/blur.avif delete mode 100644 packages/web/public/icons/logo-128.png delete mode 100644 packages/web/public/icons/logo-16.png delete mode 100644 packages/web/public/icons/logo-48.png delete mode 100644 packages/web/public/manifest.json delete mode 100644 packages/web/server/api/client.ts delete mode 100644 packages/web/server/auth.ts delete mode 100644 packages/web/tailwind.config.ts delete mode 100644 packages/web/tsconfig.json delete mode 100644 packages/web/vitest.config.ts (limited to 'packages/web') diff --git a/packages/web/README.md b/packages/web/README.md deleted file mode 100644 index c4033664..00000000 --- a/packages/web/README.md +++ /dev/null @@ -1,36 +0,0 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/packages/web/app/api/auth/[...nextauth]/route.tsx b/packages/web/app/api/auth/[...nextauth]/route.tsx deleted file mode 100644 index 2f7f1cb0..00000000 --- a/packages/web/app/api/auth/[...nextauth]/route.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { authHandler } from "@/server/auth"; - -export { authHandler as GET, authHandler as POST }; diff --git a/packages/web/app/api/trpc/[trpc]/route.ts b/packages/web/app/api/trpc/[trpc]/route.ts deleted file mode 100644 index b6753101..00000000 --- a/packages/web/app/api/trpc/[trpc]/route.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; -import { appRouter } from "@hoarder/trpc/routers/_app"; -import { createContext } from "@/server/api/client"; -import { authenticateApiKey } from "@hoarder/trpc/auth"; -import { db } from "@hoarder/db"; - -const handler = (req: Request) => - fetchRequestHandler({ - endpoint: "/api/trpc", - req, - router: appRouter, - onError: ({ path, error }) => { - if (process.env.NODE_ENV === "development") { - console.error(`❌ tRPC failed on ${path}`); - } - console.error(error); - }, - - createContext: async (opts) => { - // TODO: This is a hack until we offer a proper REST API instead of the trpc based one. - // Check if the request has an Authorization token, if it does, assume that API key authentication is requested. - const authorizationHeader = opts.req.headers.get("Authorization"); - if (authorizationHeader && authorizationHeader.startsWith("Bearer ")) { - const token = authorizationHeader.split(" ")[1]; - try { - const user = await authenticateApiKey(token); - return { user, db }; - } catch (e) { - // Fallthrough to cookie-based auth - } - } - - return createContext(); - }, - }); -export { handler as GET, handler as POST }; diff --git a/packages/web/app/dashboard/admin/page.tsx b/packages/web/app/dashboard/admin/page.tsx deleted file mode 100644 index 6babdd79..00000000 --- a/packages/web/app/dashboard/admin/page.tsx +++ /dev/null @@ -1,203 +0,0 @@ -"use client"; - -import { ActionButton } from "@/components/ui/action-button"; -import LoadingSpinner from "@/components/ui/spinner"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import { toast } from "@/components/ui/use-toast"; -import { api } from "@/lib/trpc"; -import { keepPreviousData } from "@tanstack/react-query"; -import { Trash } from "lucide-react"; -import { useSession } from "next-auth/react"; -import { useRouter } from "next/navigation"; - -function ActionsSection() { - const { mutate: recrawlLinks, isPending: isRecrawlPending } = - api.admin.recrawlAllLinks.useMutation({ - onSuccess: () => { - toast({ - description: "Recrawl enqueued", - }); - }, - onError: (e) => { - toast({ - variant: "destructive", - description: e.message, - }); - }, - }); - - const { mutate: reindexBookmarks, isPending: isReindexPending } = - api.admin.reindexAllBookmarks.useMutation({ - onSuccess: () => { - toast({ - description: "Reindex enqueued", - }); - }, - onError: (e) => { - toast({ - variant: "destructive", - description: e.message, - }); - }, - }); - - return ( - <> -

Actions

- recrawlLinks()} - > - Recrawl All Links - - reindexBookmarks()} - > - Reindex All Bookmarks - - - ); -} - -function ServerStatsSection() { - const { data: serverStats } = api.admin.stats.useQuery(undefined, { - refetchInterval: 1000, - placeholderData: keepPreviousData, - }); - - if (!serverStats) { - return ; - } - - return ( - <> -

Server Stats

- - - - Num Users - {serverStats.numUsers} - - - Num Bookmarks - {serverStats.numBookmarks} - - -
-
-

Background Jobs

- - - - Pending Crawling Jobs - {serverStats.pendingCrawls} - - - Pending Indexing Jobs - {serverStats.pendingIndexing} - - - Pending OpenAI Jobs - {serverStats.pendingOpenai} - - -
- - ); -} - -function UsersSection() { - const { data: session } = useSession(); - const invalidateUserList = api.useUtils().users.list.invalidate; - const { data: users } = api.users.list.useQuery(); - const { mutate: deleteUser, isPending: isDeletionPending } = - api.users.delete.useMutation({ - onSuccess: () => { - toast({ - description: "User deleted", - }); - invalidateUserList(); - }, - onError: (e) => { - toast({ - variant: "destructive", - description: `Something went wrong: ${e.message}`, - }); - }, - }); - - if (!users) { - return ; - } - - return ( - <> -

Users

- - - Name - Email - Role - Action - - - {users.users.map((u) => ( - - {u.name} - {u.email} - {u.role} - - deleteUser({ userId: u.id })} - loading={isDeletionPending} - disabled={session!.user.id == u.id} - > - - - - - ))} - -
- - ); -} - -export default function AdminPage() { - const router = useRouter(); - const { data: session, status } = useSession(); - - if (status == "loading") { - return ; - } - - if (!session || session.user.role != "admin") { - router.push("/"); - return; - } - - return ( -
-

Admin

-
- -
- -
- -
- ); -} diff --git a/packages/web/app/dashboard/archive/page.tsx b/packages/web/app/dashboard/archive/page.tsx deleted file mode 100644 index 69559185..00000000 --- a/packages/web/app/dashboard/archive/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import Bookmarks from "@/components/dashboard/bookmarks/Bookmarks"; - -export default async function ArchivedBookmarkPage() { - return ( -
- -
- ); -} diff --git a/packages/web/app/dashboard/bookmarks/layout.tsx b/packages/web/app/dashboard/bookmarks/layout.tsx deleted file mode 100644 index 71ee143b..00000000 --- a/packages/web/app/dashboard/bookmarks/layout.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from "react"; -import TopNav from "@/components/dashboard/bookmarks/TopNav"; -import type { Metadata } from "next"; - -export const metadata: Metadata = { - title: "Hoarder - Bookmarks", -}; - -export default function BookmarksLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( -
-
- -
-
-
{children}
-
- ); -} diff --git a/packages/web/app/dashboard/bookmarks/loading.tsx b/packages/web/app/dashboard/bookmarks/loading.tsx deleted file mode 100644 index 4e56c3c4..00000000 --- a/packages/web/app/dashboard/bookmarks/loading.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import Spinner from "@/components/ui/spinner"; - -export default function Loading() { - return ( -
-
- -
-
- ); -} diff --git a/packages/web/app/dashboard/bookmarks/page.tsx b/packages/web/app/dashboard/bookmarks/page.tsx deleted file mode 100644 index c9391d85..00000000 --- a/packages/web/app/dashboard/bookmarks/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import Bookmarks from "@/components/dashboard/bookmarks/Bookmarks"; - -export default async function BookmarksPage() { - return ; -} diff --git a/packages/web/app/dashboard/error.tsx b/packages/web/app/dashboard/error.tsx deleted file mode 100644 index 556e59a3..00000000 --- a/packages/web/app/dashboard/error.tsx +++ /dev/null @@ -1,9 +0,0 @@ -"use client"; - -export default function Error() { - return ( -
-
Something went wrong
-
- ); -} diff --git a/packages/web/app/dashboard/favourites/page.tsx b/packages/web/app/dashboard/favourites/page.tsx deleted file mode 100644 index de17461d..00000000 --- a/packages/web/app/dashboard/favourites/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import Bookmarks from "@/components/dashboard/bookmarks/Bookmarks"; - -export default async function FavouritesBookmarkPage() { - return ( -
- -
- ); -} diff --git a/packages/web/app/dashboard/layout.tsx b/packages/web/app/dashboard/layout.tsx deleted file mode 100644 index 31d592fb..00000000 --- a/packages/web/app/dashboard/layout.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Separator } from "@/components/ui/separator"; -import MobileSidebar from "@/components/dashboard/sidebar/ModileSidebar"; -import Sidebar from "@/components/dashboard/sidebar/Sidebar"; - -export default async function Dashboard({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( -
-
- -
-
-
- - -
- {children} -
-
- ); -} diff --git a/packages/web/app/dashboard/lists/[listId]/page.tsx b/packages/web/app/dashboard/lists/[listId]/page.tsx deleted file mode 100644 index 006fd3ad..00000000 --- a/packages/web/app/dashboard/lists/[listId]/page.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { api } from "@/server/api/client"; -import { getServerAuthSession } from "@/server/auth"; -import { TRPCError } from "@trpc/server"; -import { notFound, redirect } from "next/navigation"; -import ListView from "@/components/dashboard/lists/ListView"; -import DeleteListButton from "@/components/dashboard/lists/DeleteListButton"; - -export default async function ListPage({ - params, -}: { - params: { listId: string }; -}) { - const session = await getServerAuthSession(); - if (!session) { - redirect("/"); - } - - let list; - try { - list = await api.lists.get({ listId: params.listId }); - } catch (e) { - if (e instanceof TRPCError) { - if (e.code == "NOT_FOUND") { - notFound(); - } - } - throw e; - } - - const bookmarks = await api.bookmarks.getBookmarks({ ids: list.bookmarks }); - - return ( -
-
- - {list.icon} {list.name} - - -
-
- -
- ); -} diff --git a/packages/web/app/dashboard/lists/page.tsx b/packages/web/app/dashboard/lists/page.tsx deleted file mode 100644 index 88eeda47..00000000 --- a/packages/web/app/dashboard/lists/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { api } from "@/server/api/client"; -import AllListsView from "@/components/dashboard/lists/AllListsView"; - -export default async function ListsPage() { - const lists = await api.lists.list(); - - return ( -
-

📋 All Lists

-
- -
- ); -} diff --git a/packages/web/app/dashboard/not-found.tsx b/packages/web/app/dashboard/not-found.tsx deleted file mode 100644 index 64df220c..00000000 --- a/packages/web/app/dashboard/not-found.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function NotFound() { - return ( -
-
Not Found :(
-
- ); -} diff --git a/packages/web/app/dashboard/preview/[bookmarkId]/page.tsx b/packages/web/app/dashboard/preview/[bookmarkId]/page.tsx deleted file mode 100644 index 707d2b69..00000000 --- a/packages/web/app/dashboard/preview/[bookmarkId]/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { api } from "@/server/api/client"; -import BookmarkPreview from "@/components/dashboard/bookmarks/BookmarkPreview"; - -export default async function BookmarkPreviewPage({ - params, -}: { - params: { bookmarkId: string }; -}) { - const bookmark = await api.bookmarks.getBookmark({ - bookmarkId: params.bookmarkId, - }); - - return ; -} diff --git a/packages/web/app/dashboard/search/page.tsx b/packages/web/app/dashboard/search/page.tsx deleted file mode 100644 index 602f6aa0..00000000 --- a/packages/web/app/dashboard/search/page.tsx +++ /dev/null @@ -1,41 +0,0 @@ -"use client"; - -import BookmarksGrid from "@/components/dashboard/bookmarks/BookmarksGrid"; -import Loading from "../bookmarks/loading"; -import { Suspense, useRef } from "react"; -import { SearchInput } from "@/components/dashboard/search/SearchInput"; -import { useBookmarkSearch } from "@/lib/hooks/bookmark-search"; - -function SearchComp() { - const { data, isPending, isPlaceholderData } = useBookmarkSearch(); - - const inputRef: React.MutableRefObject = - useRef(null); - - return ( -
- -
- {data ? ( - b.id) }} - bookmarks={data.bookmarks} - /> - ) : ( - - )} -
- ); -} - -export default function SearchPage() { - return ( - - - - ); -} diff --git a/packages/web/app/dashboard/settings/page.tsx b/packages/web/app/dashboard/settings/page.tsx deleted file mode 100644 index 38091e6c..00000000 --- a/packages/web/app/dashboard/settings/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import ApiKeySettings from "@/components/dashboard/settings/ApiKeySettings"; -export default async function Settings() { - return ( -
-

Settings

- -
- ); -} diff --git a/packages/web/app/dashboard/tags/[tagName]/page.tsx b/packages/web/app/dashboard/tags/[tagName]/page.tsx deleted file mode 100644 index c978b86a..00000000 --- a/packages/web/app/dashboard/tags/[tagName]/page.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { getServerAuthSession } from "@/server/auth"; -import { db } from "@hoarder/db"; -import { notFound, redirect } from "next/navigation"; -import BookmarksGrid from "@/components/dashboard/bookmarks/BookmarksGrid"; -import { api } from "@/server/api/client"; -import { bookmarkTags, tagsOnBookmarks } from "@hoarder/db/schema"; -import { and, eq } from "drizzle-orm"; - -export default async function TagPage({ - params, -}: { - params: { tagName: string }; -}) { - const session = await getServerAuthSession(); - if (!session) { - redirect("/"); - } - const tagName = decodeURIComponent(params.tagName); - const tag = await db.query.bookmarkTags.findFirst({ - where: and( - eq(bookmarkTags.userId, session.user.id), - eq(bookmarkTags.name, tagName), - ), - columns: { - id: true, - }, - }); - - if (!tag) { - // TODO: Better error message when the tag is not there - notFound(); - } - - const bookmarkIds = await db.query.tagsOnBookmarks.findMany({ - where: eq(tagsOnBookmarks.tagId, tag.id), - columns: { - bookmarkId: true, - }, - }); - - const query = { - ids: bookmarkIds.map((b) => b.bookmarkId), - archived: false, - }; - - const bookmarks = await api.bookmarks.getBookmarks(query); - - return ( -
- {tagName} -
- -
- ); -} diff --git a/packages/web/app/dashboard/tags/page.tsx b/packages/web/app/dashboard/tags/page.tsx deleted file mode 100644 index 44c164e1..00000000 --- a/packages/web/app/dashboard/tags/page.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Separator } from "@/components/ui/separator"; -import { getServerAuthSession } from "@/server/auth"; -import { db } from "@hoarder/db"; -import { bookmarkTags, tagsOnBookmarks } from "@hoarder/db/schema"; -import { count, eq } from "drizzle-orm"; -import Link from "next/link"; -import { redirect } from "next/navigation"; - -function TagPill({ name, count }: { name: string; count: number }) { - return ( - - {name} {count} - - ); -} - -export default async function TagsPage() { - const session = await getServerAuthSession(); - if (!session) { - redirect("/"); - } - - let tags = await db - .select({ - id: tagsOnBookmarks.tagId, - name: bookmarkTags.name, - count: count(), - }) - .from(tagsOnBookmarks) - .where(eq(bookmarkTags.userId, session.user.id)) - .groupBy(tagsOnBookmarks.tagId) - .innerJoin(bookmarkTags, eq(bookmarkTags.id, tagsOnBookmarks.tagId)); - - // Sort tags by usage desc - tags = tags.sort((a, b) => b.count - a.count); - - let tagPill; - if (tags.length) { - tagPill = tags.map((t) => ( - - )); - } else { - tagPill = "No Tags"; - } - - return ( -
- All Tags -
-
{tagPill}
-
- ); -} diff --git a/packages/web/app/favicon.ico b/packages/web/app/favicon.ico deleted file mode 100644 index 750e3c04..00000000 Binary files a/packages/web/app/favicon.ico and /dev/null differ diff --git a/packages/web/app/globals.css b/packages/web/app/globals.css deleted file mode 100644 index 8abdb15c..00000000 --- a/packages/web/app/globals.css +++ /dev/null @@ -1,76 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - :root { - --background: 0 0% 100%; - --foreground: 222.2 84% 4.9%; - - --card: 0 0% 100%; - --card-foreground: 222.2 84% 4.9%; - - --popover: 0 0% 100%; - --popover-foreground: 222.2 84% 4.9%; - - --primary: 222.2 47.4% 11.2%; - --primary-foreground: 210 40% 98%; - - --secondary: 210 40% 96.1%; - --secondary-foreground: 222.2 47.4% 11.2%; - - --muted: 210 40% 96.1%; - --muted-foreground: 215.4 16.3% 46.9%; - - --accent: 210 40% 96.1%; - --accent-foreground: 222.2 47.4% 11.2%; - - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 210 40% 98%; - - --border: 214.3 31.8% 91.4%; - --input: 214.3 31.8% 91.4%; - --ring: 222.2 84% 4.9%; - - --radius: 0.5rem; - } - - .dark { - --background: 222.2 84% 4.9%; - --foreground: 210 40% 98%; - - --card: 222.2 84% 4.9%; - --card-foreground: 210 40% 98%; - - --popover: 222.2 84% 4.9%; - --popover-foreground: 210 40% 98%; - - --primary: 210 40% 98%; - --primary-foreground: 222.2 47.4% 11.2%; - - --secondary: 217.2 32.6% 17.5%; - --secondary-foreground: 210 40% 98%; - - --muted: 217.2 32.6% 17.5%; - --muted-foreground: 215 20.2% 65.1%; - - --accent: 217.2 32.6% 17.5%; - --accent-foreground: 210 40% 98%; - - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 210 40% 98%; - - --border: 217.2 32.6% 17.5%; - --input: 217.2 32.6% 17.5%; - --ring: 212.7 26.8% 83.9%; - } -} - -@layer base { - * { - @apply border-border; - } - body { - @apply bg-background text-foreground; - } -} diff --git a/packages/web/app/layout.tsx b/packages/web/app/layout.tsx deleted file mode 100644 index b1790a1f..00000000 --- a/packages/web/app/layout.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import type { Metadata } from "next"; -import { Inter } from "next/font/google"; -import "./globals.css"; -import React from "react"; -import { Toaster } from "@/components/ui/toaster"; -import Providers from "@/lib/providers"; -import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; -import { getServerAuthSession } from "@/server/auth"; -import type { Viewport } from "next"; - -const inter = Inter({ subsets: ["latin"] }); - -export const metadata: Metadata = { - title: "Hoarder", - applicationName: "Hoarder", - description: "Your AI powered second brain", - manifest: "/manifest.json", - appleWebApp: { - capable: true, - title: "Hoarder", - }, - formatDetection: { - telephone: false, - }, -}; - -export const viewport: Viewport = { - width: "device-width", - initialScale: 1, - maximumScale: 1, - userScalable: false, -}; - -export default async function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - const session = await getServerAuthSession(); - return ( - - - - {children} - - - - - - ); -} diff --git a/packages/web/app/page.tsx b/packages/web/app/page.tsx deleted file mode 100644 index f467b64b..00000000 --- a/packages/web/app/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { getServerAuthSession } from "@/server/auth"; -import { redirect } from "next/navigation"; - -export default async function Home() { - // TODO: Home currently just redirects between pages until we build a proper landing page - const session = await getServerAuthSession(); - if (!session) { - redirect("/signin"); - } - - redirect("/dashboard/bookmarks"); -} diff --git a/packages/web/app/signin/page.tsx b/packages/web/app/signin/page.tsx deleted file mode 100644 index fed71b62..00000000 --- a/packages/web/app/signin/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { PackageOpen } from "lucide-react"; -import SignInForm from "@/components/signin/SignInForm"; -import { redirect } from "next/dist/client/components/navigation"; -import { getServerAuthSession } from "@/server/auth"; - -export default async function SignInPage() { - const session = await getServerAuthSession(); - if (session) { - redirect("/"); - } - - return ( -
-
- - - -

Hoarder

-
-
- -
-
- ); -} diff --git a/packages/web/components.json b/packages/web/components.json deleted file mode 100644 index fa674c93..00000000 --- a/packages/web/components.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "default", - "rsc": true, - "tsx": true, - "tailwind": { - "config": "tailwind.config.ts", - "css": "app/globals.css", - "baseColor": "slate", - "cssVariables": true, - "prefix": "" - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils" - } -} diff --git a/packages/web/components/dashboard/bookmarks/AddLinkButton.tsx b/packages/web/components/dashboard/bookmarks/AddLinkButton.tsx deleted file mode 100644 index 5973f909..00000000 --- a/packages/web/components/dashboard/bookmarks/AddLinkButton.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { Form, FormControl, FormField, FormItem } from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { useForm, SubmitErrorHandler } from "react-hook-form"; -import { z } from "zod"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { toast } from "@/components/ui/use-toast"; -import { api } from "@/lib/trpc"; -import { ActionButton } from "@/components/ui/action-button"; -import { Button } from "@/components/ui/button"; -import { - Dialog, - DialogClose, - DialogContent, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; -import { useState } from "react"; - -export function AddLinkButton({ children }: { children: React.ReactNode }) { - const [isOpen, setOpen] = useState(false); - - const formSchema = z.object({ - url: z.string().url({ message: "The link must be a valid URL" }), - }); - const form = useForm>({ - resolver: zodResolver(formSchema), - defaultValues: { - url: "", - }, - }); - - const invalidateBookmarksCache = api.useUtils().bookmarks.invalidate; - const createBookmarkMutator = api.bookmarks.createBookmark.useMutation({ - onSuccess: () => { - invalidateBookmarksCache(); - form.reset(); - setOpen(false); - }, - onError: () => { - toast({ description: "Something went wrong", variant: "destructive" }); - }, - }); - - const onError: SubmitErrorHandler> = (errors) => { - toast({ - description: Object.values(errors) - .map((v) => v.message) - .join("\n"), - variant: "destructive", - }); - }; - - return ( - - {children} - -
- - Add Link - - - createBookmarkMutator.mutate({ url: value.url, type: "link" }), - onError, - )} - > - { - return ( - - - - - - ); - }} - /> - - - - - - Add - - - - -
-
- ); -} diff --git a/packages/web/components/dashboard/bookmarks/AddToListModal.tsx b/packages/web/components/dashboard/bookmarks/AddToListModal.tsx deleted file mode 100644 index c9fd5da0..00000000 --- a/packages/web/components/dashboard/bookmarks/AddToListModal.tsx +++ /dev/null @@ -1,168 +0,0 @@ -import { ActionButton } from "@/components/ui/action-button"; -import { Button } from "@/components/ui/button"; -import { - Dialog, - DialogClose, - DialogContent, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { - Form, - FormControl, - FormField, - FormItem, - FormMessage, -} from "@/components/ui/form"; - -import { toast } from "@/components/ui/use-toast"; -import { api } from "@/lib/trpc"; -import { useState } from "react"; - -import { - Select, - SelectContent, - SelectGroup, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import LoadingSpinner from "@/components/ui/spinner"; -import { z } from "zod"; -import { useForm } from "react-hook-form"; -import { zodResolver } from "@hookform/resolvers/zod"; - -export default function AddToListModal({ - bookmarkId, - open, - setOpen, -}: { - bookmarkId: string; - open: boolean; - setOpen: (open: boolean) => void; -}) { - const formSchema = z.object({ - listId: z.string({ - required_error: "Please select a list", - }), - }); - const form = useForm>({ - resolver: zodResolver(formSchema), - }); - - const { data: lists, isPending: isFetchingListsPending } = - api.lists.list.useQuery(); - - const listInvalidationFunction = api.useUtils().lists.get.invalidate; - const bookmarksInvalidationFunction = - api.useUtils().bookmarks.getBookmarks.invalidate; - - const { mutate: addToList, isPending: isAddingToListPending } = - api.lists.addToList.useMutation({ - onSuccess: (_resp, req) => { - toast({ - description: "List has been updated!", - }); - listInvalidationFunction({ listId: req.listId }); - bookmarksInvalidationFunction(); - }, - onError: (e) => { - if (e.data?.code == "BAD_REQUEST") { - toast({ - variant: "destructive", - description: e.message, - }); - } else { - toast({ - variant: "destructive", - title: "Something went wrong", - }); - } - }, - }); - - const isPending = isFetchingListsPending || isAddingToListPending; - - return ( - - -
- { - addToList({ - bookmarkId: bookmarkId, - listId: value.listId, - }); - })} - > - - Add to List - - -
- {lists ? ( - { - return ( - - - - - - - ); - }} - /> - ) : ( - - )} -
- - - - - - Add - - -
- -
-
- ); -} - -export function useAddToListModal(bookmarkId: string) { - const [open, setOpen] = useState(false); - - return { - open, - setOpen, - content: ( - - ), - }; -} diff --git a/packages/web/components/dashboard/bookmarks/BookmarkCardSkeleton.tsx b/packages/web/components/dashboard/bookmarks/BookmarkCardSkeleton.tsx deleted file mode 100644 index 1f5fa433..00000000 --- a/packages/web/components/dashboard/bookmarks/BookmarkCardSkeleton.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { - ImageCard, - ImageCardBody, - ImageCardContent, - ImageCardFooter, - ImageCardTitle, - ImageCardBanner, -} from "@/components/ui/imageCard"; -import { Skeleton } from "@/components/ui/skeleton"; - -export default function BookmarkCardSkeleton() { - return ( - - - - - - - - - - - - - ); -} diff --git a/packages/web/components/dashboard/bookmarks/BookmarkOptions.tsx b/packages/web/components/dashboard/bookmarks/BookmarkOptions.tsx deleted file mode 100644 index 4f08ebee..00000000 --- a/packages/web/components/dashboard/bookmarks/BookmarkOptions.tsx +++ /dev/null @@ -1,185 +0,0 @@ -"use client"; - -import { useToast } from "@/components/ui/use-toast"; -import { api } from "@/lib/trpc"; -import { ZBookmark, ZBookmarkedLink } from "@hoarder/trpc/types/bookmarks"; -import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { - Archive, - Link, - List, - MoreHorizontal, - Pencil, - RotateCw, - Star, - Tags, - Trash2, -} from "lucide-react"; -import { useTagModel } from "./TagModal"; -import { useState } from "react"; -import { BookmarkedTextEditor } from "./BookmarkedTextEditor"; -import { useAddToListModal } from "./AddToListModal"; - -export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) { - const { toast } = useToast(); - const linkId = bookmark.id; - - const { setOpen: setTagModalIsOpen, content: tagModal } = - useTagModel(bookmark); - const { setOpen: setAddToListModalOpen, content: addToListModal } = - useAddToListModal(bookmark.id); - - const [isTextEditorOpen, setTextEditorOpen] = useState(false); - - const invalidateAllBookmarksCache = - api.useUtils().bookmarks.getBookmarks.invalidate; - - const invalidateBookmarkCache = - api.useUtils().bookmarks.getBookmark.invalidate; - - const onError = () => { - toast({ - variant: "destructive", - title: "Something went wrong", - description: "There was a problem with your request.", - }); - }; - const deleteBookmarkMutator = api.bookmarks.deleteBookmark.useMutation({ - onSuccess: () => { - toast({ - description: "The bookmark has been deleted!", - }); - }, - onError, - onSettled: () => { - invalidateAllBookmarksCache(); - }, - }); - - const updateBookmarkMutator = api.bookmarks.updateBookmark.useMutation({ - onSuccess: () => { - toast({ - description: "The bookmark has been updated!", - }); - }, - onError, - onSettled: () => { - invalidateBookmarkCache({ bookmarkId: bookmark.id }); - invalidateAllBookmarksCache(); - }, - }); - - const crawlBookmarkMutator = api.bookmarks.recrawlBookmark.useMutation({ - onSuccess: () => { - toast({ - description: "Re-fetch has been enqueued!", - }); - }, - onError, - onSettled: () => { - invalidateBookmarkCache({ bookmarkId: bookmark.id }); - }, - }); - - return ( - <> - {tagModal} - {addToListModal} - - - - - - - {bookmark.content.type === "text" && ( - setTextEditorOpen(true)}> - - Edit - - )} - - updateBookmarkMutator.mutate({ - bookmarkId: linkId, - favourited: !bookmark.favourited, - }) - } - > - - {bookmark.favourited ? "Un-favourite" : "Favourite"} - - - updateBookmarkMutator.mutate({ - bookmarkId: linkId, - archived: !bookmark.archived, - }) - } - > - - {bookmark.archived ? "Un-archive" : "Archive"} - - {bookmark.content.type === "link" && ( - { - navigator.clipboard.writeText( - (bookmark.content as ZBookmarkedLink).url, - ); - toast({ - description: "Link was added to your clipboard!", - }); - }} - > - - Copy Link - - )} - setTagModalIsOpen(true)}> - - Edit Tags - - - setAddToListModalOpen(true)}> - - Add to List - - - {bookmark.content.type === "link" && ( - - crawlBookmarkMutator.mutate({ bookmarkId: bookmark.id }) - } - > - - Refresh - - )} - - deleteBookmarkMutator.mutate({ bookmarkId: bookmark.id }) - } - > - - Delete - - - - - ); -} diff --git a/packages/web/components/dashboard/bookmarks/BookmarkPreview.tsx b/packages/web/components/dashboard/bookmarks/BookmarkPreview.tsx deleted file mode 100644 index 2a8ae1b1..00000000 --- a/packages/web/components/dashboard/bookmarks/BookmarkPreview.tsx +++ /dev/null @@ -1,101 +0,0 @@ -"use client"; - -import { BackButton } from "@/components/ui/back-button"; -import { Skeleton } from "@/components/ui/skeleton"; -import { isBookmarkStillCrawling } from "@/lib/bookmarkUtils"; -import { api } from "@/lib/trpc"; -import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; -import { ArrowLeftCircle, CalendarDays, ExternalLink } from "lucide-react"; -import Link from "next/link"; -import Markdown from "react-markdown"; - -export default function BookmarkPreview({ - initialData, -}: { - initialData: ZBookmark; -}) { - const { data: bookmark } = api.bookmarks.getBookmark.useQuery( - { - bookmarkId: initialData.id, - }, - { - initialData, - refetchInterval: (query) => { - const data = query.state.data; - if (!data) { - return false; - } - // If the link is not crawled or not tagged - if (isBookmarkStillCrawling(data)) { - return 1000; - } - return false; - }, - }, - ); - - const linkHeader = bookmark.content.type == "link" && ( -
-

- {bookmark.content.title || bookmark.content.url} -

- - View Original - - -
- ); - - let content; - switch (bookmark.content.type) { - case "link": { - if (!bookmark.content.htmlContent) { - content = ( -
Failed to fetch link content ...
- ); - } else { - content = ( -
- ); - } - break; - } - case "text": { - content = {bookmark.content.text}; - break; - } - } - - return ( -
-
- - - -
- - {bookmark.createdAt.toLocaleString()} - -
-
-
- {linkHeader} -
- {isBookmarkStillCrawling(bookmark) ? ( -
- - - -
- ) : ( - content - )} -
-
- ); -} diff --git a/packages/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx b/packages/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx deleted file mode 100644 index a5b58f1a..00000000 --- a/packages/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; -import { - Dialog, - DialogClose, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { ActionButton } from "@/components/ui/action-button"; -import { Button } from "@/components/ui/button"; -import { Textarea } from "@/components/ui/textarea"; -import { api } from "@/lib/trpc"; -import { useState } from "react"; -import { toast } from "@/components/ui/use-toast"; - -export function BookmarkedTextEditor({ - bookmark, - open, - setOpen, -}: { - bookmark?: ZBookmark; - open: boolean; - setOpen: (open: boolean) => void; -}) { - const isNewBookmark = bookmark === undefined; - const [noteText, setNoteText] = useState( - bookmark && bookmark.content.type == "text" ? bookmark.content.text : "", - ); - - const invalidateAllBookmarksCache = - api.useUtils().bookmarks.getBookmarks.invalidate; - const invalidateOneBookmarksCache = - api.useUtils().bookmarks.getBookmark.invalidate; - - const { mutate: createBookmarkMutator, isPending: isCreationPending } = - api.bookmarks.createBookmark.useMutation({ - onSuccess: () => { - invalidateAllBookmarksCache(); - toast({ - description: "Note created!", - }); - setOpen(false); - setNoteText(""); - }, - onError: () => { - toast({ description: "Something went wrong", variant: "destructive" }); - }, - }); - const { mutate: updateBookmarkMutator, isPending: isUpdatePending } = - api.bookmarks.updateBookmarkText.useMutation({ - onSuccess: () => { - invalidateOneBookmarksCache({ - bookmarkId: bookmark!.id, - }); - toast({ - description: "Note updated!", - }); - setOpen(false); - }, - onError: () => { - toast({ description: "Something went wrong", variant: "destructive" }); - }, - }); - const isPending = isCreationPending || isUpdatePending; - - const onSave = () => { - if (isNewBookmark) { - createBookmarkMutator({ - type: "text", - text: noteText, - }); - } else { - updateBookmarkMutator({ - bookmarkId: bookmark.id, - text: noteText, - }); - } - }; - - return ( - - - - {isNewBookmark ? "New Note" : "Edit Note"} - - Write your note with markdown support - - -