From 64fb87d0ceb591a49aacad39bf5e885cab7decfa Mon Sep 17 00:00:00 2001 From: MohamedBassem Date: Tue, 19 Mar 2024 12:41:06 +0000 Subject: feature(web): Add support for demo mode --- apps/web/app/dashboard/layout.tsx | 2 ++ apps/web/app/layout.tsx | 4 +++- apps/web/components/DemoModeBanner.tsx | 7 +++++++ .../dashboard/bookmarks/BookmarkOptions.tsx | 7 +++++++ .../dashboard/bookmarks/BookmarksGrid.tsx | 1 + .../components/dashboard/bookmarks/TagsEditor.tsx | 3 +++ .../components/dashboard/sidebar/NewListModal.tsx | 17 +++++++++++++---- apps/web/components/signin/CredentialsForm.tsx | 6 +++++- apps/web/components/ui/action-button.tsx | 9 ++++++++- apps/web/lib/clientConfig.tsx | 11 +++++++++++ apps/web/lib/providers.tsx | 21 ++++++++++++++------- 11 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 apps/web/components/DemoModeBanner.tsx create mode 100644 apps/web/lib/clientConfig.tsx (limited to 'apps') diff --git a/apps/web/app/dashboard/layout.tsx b/apps/web/app/dashboard/layout.tsx index 27e06955..b79fd0f9 100644 --- a/apps/web/app/dashboard/layout.tsx +++ b/apps/web/app/dashboard/layout.tsx @@ -1,6 +1,7 @@ import MobileSidebar from "@/components/dashboard/sidebar/ModileSidebar"; import Sidebar from "@/components/dashboard/sidebar/Sidebar"; import UploadDropzone from "@/components/dashboard/UploadDropzone"; +import DemoModeBanner from "@/components/DemoModeBanner"; import { Separator } from "@/components/ui/separator"; export default async function Dashboard({ @@ -14,6 +15,7 @@ export default async function Dashboard({
+
diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 6ec9c3e4..395d7297 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -10,6 +10,8 @@ import Providers from "@/lib/providers"; import { getServerAuthSession } from "@/server/auth"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; +import { clientConfig } from "@hoarder/shared/config"; + const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { @@ -42,7 +44,7 @@ export default async function RootLayout({ return ( - + {children} diff --git a/apps/web/components/DemoModeBanner.tsx b/apps/web/components/DemoModeBanner.tsx new file mode 100644 index 00000000..6250be87 --- /dev/null +++ b/apps/web/components/DemoModeBanner.tsx @@ -0,0 +1,7 @@ +export default function DemoModeBanner() { + return ( +
+ Demo mode is on. All modifications are disabled. +
+ ); +} diff --git a/apps/web/components/dashboard/bookmarks/BookmarkOptions.tsx b/apps/web/components/dashboard/bookmarks/BookmarkOptions.tsx index 3656a435..692d7d78 100644 --- a/apps/web/components/dashboard/bookmarks/BookmarkOptions.tsx +++ b/apps/web/components/dashboard/bookmarks/BookmarkOptions.tsx @@ -9,6 +9,7 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { useToast } from "@/components/ui/use-toast"; +import { useClientConfig } from "@/lib/clientConfig"; import { api } from "@/lib/trpc"; import { Archive, @@ -32,6 +33,8 @@ export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) { const { toast } = useToast(); const linkId = bookmark.id; + const demoMode = useClientConfig().demoMode; + const { setOpen: setTagModalIsOpen, content: tagModal } = useTagModel(bookmark); const { setOpen: setAddToListModalOpen, content: addToListModal } = @@ -115,6 +118,7 @@ export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) { )} updateBookmarkMutator.mutate({ bookmarkId: linkId, @@ -126,6 +130,7 @@ export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) { {bookmark.favourited ? "Un-favourite" : "Favourite"} updateBookmarkMutator.mutate({ bookmarkId: linkId, @@ -163,6 +168,7 @@ export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) { {bookmark.content.type === "link" && ( crawlBookmarkMutator.mutate({ bookmarkId: bookmark.id }) } @@ -172,6 +178,7 @@ export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) { )} deleteBookmarkMutator.mutate({ bookmarkId: bookmark.id }) diff --git a/apps/web/components/dashboard/bookmarks/BookmarksGrid.tsx b/apps/web/components/dashboard/bookmarks/BookmarksGrid.tsx index b40e6e42..4b0dc4fd 100644 --- a/apps/web/components/dashboard/bookmarks/BookmarksGrid.tsx +++ b/apps/web/components/dashboard/bookmarks/BookmarksGrid.tsx @@ -92,6 +92,7 @@ export default function BookmarksGrid({ {hasNextPage && ( fetchNextPage()} className="mx-auto w-min" diff --git a/apps/web/components/dashboard/bookmarks/TagsEditor.tsx b/apps/web/components/dashboard/bookmarks/TagsEditor.tsx index 38f01bdd..4cccfc02 100644 --- a/apps/web/components/dashboard/bookmarks/TagsEditor.tsx +++ b/apps/web/components/dashboard/bookmarks/TagsEditor.tsx @@ -1,5 +1,6 @@ import type { ActionMeta } from "react-select"; import { toast } from "@/components/ui/use-toast"; +import { useClientConfig } from "@/lib/clientConfig"; import { api } from "@/lib/trpc"; import { cn } from "@/lib/utils"; import { Sparkles } from "lucide-react"; @@ -15,6 +16,7 @@ interface EditableTag { } export function TagsEditor({ bookmark }: { bookmark: ZBookmark }) { + const demoMode = useClientConfig().demoMode; const bookmarkInvalidationFunction = api.useUtils().bookmarks.getBookmark.invalidate; @@ -79,6 +81,7 @@ export function TagsEditor({ bookmark }: { bookmark: ZBookmark }) { return ( ({ diff --git a/apps/web/components/dashboard/sidebar/NewListModal.tsx b/apps/web/components/dashboard/sidebar/NewListModal.tsx index e244411d..31c35d6c 100644 --- a/apps/web/components/dashboard/sidebar/NewListModal.tsx +++ b/apps/web/components/dashboard/sidebar/NewListModal.tsx @@ -67,10 +67,19 @@ export default function NewListModal() { }, onError: (e) => { if (e.data?.code == "BAD_REQUEST") { - toast({ - variant: "destructive", - description: e.message, - }); + if (e.data.zodError) { + toast({ + variant: "destructive", + description: Object.values(e.data.zodError.fieldErrors) + .flat() + .join("\n"), + }); + } else { + toast({ + variant: "destructive", + description: e.message, + }); + } } else { toast({ variant: "destructive", diff --git a/apps/web/components/signin/CredentialsForm.tsx b/apps/web/components/signin/CredentialsForm.tsx index 59dfeb21..8e1423eb 100644 --- a/apps/web/components/signin/CredentialsForm.tsx +++ b/apps/web/components/signin/CredentialsForm.tsx @@ -86,7 +86,11 @@ function SignIn() { ); }} /> - + Sign In
diff --git a/apps/web/components/ui/action-button.tsx b/apps/web/components/ui/action-button.tsx index 11b02a5f..5b862e07 100644 --- a/apps/web/components/ui/action-button.tsx +++ b/apps/web/components/ui/action-button.tsx @@ -1,3 +1,5 @@ +import { useClientConfig } from "@/lib/clientConfig"; + import type { ButtonProps } from "./button"; import { Button } from "./button"; import LoadingSpinner from "./spinner"; @@ -7,13 +9,18 @@ export function ActionButton({ loading, spinner, disabled, + ignoreDemoMode = false, ...props }: ButtonProps & { loading: boolean; spinner?: React.ReactNode; + ignoreDemoMode?: boolean; }) { + const clientConfig = useClientConfig(); spinner ||= ; - if (disabled !== undefined) { + if (!ignoreDemoMode && clientConfig.demoMode) { + disabled = true; + } else if (disabled !== undefined) { disabled ||= loading; } else if (loading) { disabled = true; diff --git a/apps/web/lib/clientConfig.tsx b/apps/web/lib/clientConfig.tsx new file mode 100644 index 00000000..fac76d3b --- /dev/null +++ b/apps/web/lib/clientConfig.tsx @@ -0,0 +1,11 @@ +import { createContext, useContext } from "react"; + +import type { ClientConfig } from "@hoarder/shared/config"; + +export const ClientConfigCtx = createContext({ + demoMode: false, +}); + +export function useClientConfig() { + return useContext(ClientConfigCtx); +} diff --git a/apps/web/lib/providers.tsx b/apps/web/lib/providers.tsx index db51c361..ce667f8d 100644 --- a/apps/web/lib/providers.tsx +++ b/apps/web/lib/providers.tsx @@ -7,6 +7,9 @@ import { httpBatchLink, loggerLink } from "@trpc/client"; import { SessionProvider } from "next-auth/react"; import superjson from "superjson"; +import type { ClientConfig } from "@hoarder/shared/config"; + +import { ClientConfigCtx } from "./clientConfig"; import { api } from "./trpc"; function makeQueryClient() { @@ -40,9 +43,11 @@ function getQueryClient() { export default function Providers({ children, session, + clientConfig, }: { children: React.ReactNode; session: Session | null; + clientConfig: ClientConfig; }) { const queryClient = getQueryClient(); @@ -64,12 +69,14 @@ export default function Providers({ ); return ( - - - - {children} - - - + + + + + {children} + + + + ); } -- cgit v1.2.3-70-g09d2