Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

export function RulesTab() {
return (
<div>
<div className="mt-8">
<RulesPrompt />

<Tabs defaultValue="list" searchParam="format">
Expand Down
5 changes: 0 additions & 5 deletions apps/web/app/(app)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,7 @@ export default async function AppLayout({
<QueueInitializer />
<AssessUser />
<SentryIdentify email={session.user.email} />
{/* <Suspense>
<CrispWithNoSSR email={session.user.email} />
</Suspense> */}
</ErrorBoundary>
</AppProviders>
);
}

// const CrispWithNoSSR = dynamic(() => import("@/components/CrispChat"));
22 changes: 11 additions & 11 deletions apps/web/components/CrispChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import { useEffect, useState } from "react";
import { Crisp } from "crisp-sdk-web";
import { usePathname } from "next/navigation";
import { env } from "@/env";
import { useSidebar } from "@/components/ui/sidebar";
import { useAccount } from "@/providers/EmailAccountProvider";

const CrispChat = ({ email }: { email?: string }) => {
const pathname = usePathname();
const CrispChat = () => {
const { state } = useSidebar();

const [isConfigured, setIsConfigured] = useState(false);
const isChatOpen = state.includes("chat-sidebar");

useEffect(() => {
if (!env.NEXT_PUBLIC_CRISP_WEBSITE_ID) return;
Expand All @@ -18,25 +20,23 @@ const CrispChat = ({ email }: { email?: string }) => {
setIsConfigured(true);
}, []);

const { userEmail } = useAccount();

useEffect(() => {
if (!env.NEXT_PUBLIC_CRISP_WEBSITE_ID || !isConfigured) return;

if (email) Crisp.user.setEmail(email);
}, [email, isConfigured]);
if (userEmail) Crisp.user.setEmail(userEmail);
}, [userEmail, isConfigured]);

useEffect(() => {
if (!env.NEXT_PUBLIC_CRISP_WEBSITE_ID || !isConfigured) return;

if (
pathname.includes("/assistant") ||
pathname.includes("/automation") ||
pathname.includes("/reply-zero")
) {
if (isChatOpen) {
Crisp.chat.hide();
} else {
Crisp.chat.show();
}
}, [pathname, isConfigured]);
}, [isConfigured, isChatOpen]);

return null;
};
Expand Down
7 changes: 7 additions & 0 deletions apps/web/components/SideNavWithTopNav.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"use client";

import { Suspense } from "react";
import dynamic from "next/dynamic";
import { usePathname } from "next/navigation";
import { Toaster } from "@/components/Toast";
import { NavBottom } from "@/components/NavBottom";
Expand All @@ -12,6 +14,8 @@ import { SideNav } from "@/components/SideNav";
import { SidebarRight } from "@/components/SidebarRight";
import { cn } from "@/utils";

const CrispWithNoSSR = dynamic(() => import("@/components/CrispChat"));

Comment on lines +17 to +18
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Make the dynamic import truly client-only and Suspense-aware

Without options, dynamic can attempt SSR and your Suspense wrapper won’t take effect. Enable no-SSR and Suspense.

Apply:

-const CrispWithNoSSR = dynamic(() => import("@/components/CrispChat"));
+const CrispWithNoSSR = dynamic(() => import("@/components/CrispChat"), {
+  ssr: false,
+  suspense: true,
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const CrispWithNoSSR = dynamic(() => import("@/components/CrispChat"));
const CrispWithNoSSR = dynamic(() => import("@/components/CrispChat"), {
ssr: false,
suspense: true,
});
🤖 Prompt for AI Agents
In apps/web/components/SideNavWithTopNav.tsx around lines 17 to 18, the dynamic
import for CrispChat is currently created without options so it may be
server-rendered and bypass your Suspense wrapper; update the dynamic call to be
client-only and Suspense-aware by enabling ssr: false and suspense: true in the
dynamic options so the component is only loaded on the client and works with
your Suspense fallback.

function ContentWrapper({ children }: { children: React.ReactNode }) {
const { state } = useSidebar();
const isRightSidebarOpen = state.includes("chat-sidebar");
Expand All @@ -33,6 +37,9 @@ function ContentWrapper({ children }: { children: React.ReactNode }) {
<NavBottom />
</div>
</SidebarInset>
<Suspense>
<CrispWithNoSSR />
</Suspense>
Comment on lines +40 to +42
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Provide a Suspense fallback

React’s Suspense expects a fallback; also now that dynamic uses suspense: true, this will render correctly.

Apply:

-      <Suspense>
-        <CrispWithNoSSR />
-      </Suspense>
+      <Suspense fallback={null}>
+        <CrispWithNoSSR />
+      </Suspense>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Suspense>
<CrispWithNoSSR />
</Suspense>
<Suspense fallback={null}>
<CrispWithNoSSR />
</Suspense>
🤖 Prompt for AI Agents
In apps/web/components/SideNavWithTopNav.tsx around lines 40 to 42, the Suspense
wrapper lacks a fallback prop which React requires (especially since the
component is rendered with suspense: true). Wrap <CrispWithNoSSR /> in Suspense
providing a meaningful fallback (e.g., a small loader, skeleton, or null) by
adding the fallback attribute to the Suspense element so the UI shows during
async loading.

</div>
);
}
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v2.6.12
v2.6.13
Loading