Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion apps/web/app/(app)/premium/PremiumModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useState } from "react";
import { Dialog, DialogContent } from "@/components/ui/dialog";
import { Pricing } from "@/app/(app)/premium/Pricing";
import Pricing from "@/app/(app)/premium/Pricing";

export function usePremiumModal() {
const [isOpen, setIsOpen] = useState(false);
Expand Down
6 changes: 4 additions & 2 deletions apps/web/app/(app)/premium/Pricing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ const frequencies = [
{ value: "annually" as const, label: "Annually", priceSuffix: "/month" },
];

export function Pricing(props: {
export type PricingProps = {
header?: React.ReactNode;
showSkipUpgrade?: boolean;
className?: string;
}) {
};

export default function Pricing(props: PricingProps) {
const { isPremium, premium, isLoading, error, data } = usePremium();

const isLoggedIn = !!data?.id;
Expand Down
12 changes: 12 additions & 0 deletions apps/web/app/(app)/premium/PricingLazy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Loading } from "@/components/Loading";
import dynamic from "next/dynamic";
import { Suspense } from "react";
import type { PricingProps } from "./Pricing";

const PricingComponent = dynamic(() => import("./Pricing"));

export const PricingLazy = (props: PricingProps) => (
<Suspense fallback={<Loading />}>
<PricingComponent {...props} />
</Suspense>
);
4 changes: 2 additions & 2 deletions apps/web/app/(app)/premium/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Pricing } from "@/app/(app)/premium/Pricing";
import { PricingLazy } from "@/app/(app)/premium/PricingLazy";

export default function Premium() {
return (
<div className="bg-white pb-20">
<Pricing />
<PricingLazy />
</div>
);
}
19 changes: 8 additions & 11 deletions apps/web/app/(landing)/components/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import { Suspense } from "react";
import { SparklesIcon } from "lucide-react";
import { CardBasic } from "@/components/ui/card";
import { Container } from "@/components/Container";
Expand Down Expand Up @@ -120,16 +119,14 @@ export default function Components() {
<div>
<div className="underline">Tabs</div>
<div className="mt-4">
<Suspense>
<Tabs defaultValue="account" className="w-[400px]">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
</TabsList>
<TabsContent value="account">Account content</TabsContent>
<TabsContent value="password">Password content</TabsContent>
</Tabs>
</Suspense>
<Tabs defaultValue="account" className="w-[400px]">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
</TabsList>
<TabsContent value="account">Account content</TabsContent>
<TabsContent value="password">Password content</TabsContent>
</Tabs>
</div>
</div>

Expand Down
5 changes: 4 additions & 1 deletion apps/web/app/(landing)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Suspense } from "react";
import type { Metadata } from "next";
import { redirect } from "next/navigation";
import Link from "next/link";
Expand Down Expand Up @@ -37,7 +38,9 @@ export default async function AuthenticationPage(props: {
</p>
</div>
<div className="mt-4">
<LoginForm />
<Suspense>
<LoginForm />
</Suspense>
Comment on lines +41 to +43

@coderabbitai coderabbitai Bot Jun 5, 2025

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.

⚠️ Potential issue

Remove unnecessary Suspense wrapper

The LoginForm component doesn't appear to require Suspense wrapping based on the code analysis:

  1. LoginForm is not lazy-loaded (no React.lazy())
  2. It doesn't use any async operations that would suspend
  3. No fallback UI is provided, which could lead to issues if Suspense triggers

Since LoginForm is a regular synchronous component using standard hooks (useState, useSearchParams), the Suspense wrapper is unnecessary.

-          <Suspense>
-            <LoginForm />
-          </Suspense>
+          <LoginForm />

Also remove the unused import:

-import { Suspense } from "react";
📝 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>
<LoginForm />
</Suspense>
// apps/web/app/(landing)/login/page.tsx
import React from "react";
-import { Suspense } from "react";
import LoginForm from "./LoginForm";
export default function LoginPage() {
return (
- <Suspense>
- <LoginForm />
- </Suspense>
+ <LoginForm />
);
}
🤖 Prompt for AI Agents
In apps/web/app/(landing)/login/page.tsx around lines 41 to 43, remove the
Suspense wrapper around the LoginForm component because LoginForm is a
synchronous component that does not require Suspense. Also, remove the unused
Suspense import from the file to clean up unused code.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

It is needed as it has useSearchParams inside it

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.

@elie222 Thank you for the clarification! You're absolutely right. I understand now that the Suspense wrapper is necessary because useSearchParams can trigger suspense in Next.js App Router. I'll make note of this for future reviews.


✏️ Learnings added
Learnt from: elie222
PR: elie222/inbox-zero#485
File: apps/web/app/(landing)/login/page.tsx:41-43
Timestamp: 2025-06-05T09:49:12.138Z
Learning: In Next.js App Router, components that use the `useSearchParams` hook require a Suspense boundary to handle the asynchronous nature of search parameter access. The Suspense wrapper is necessary and should not be removed when a component uses useSearchParams.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

</div>

{searchParams?.error && (
Expand Down
5 changes: 2 additions & 3 deletions apps/web/app/(landing)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Suspense } from "react";
import type { Metadata } from "next";
import { HeroHome } from "@/app/(landing)/home/Hero";
import { FeaturesHome } from "@/app/(landing)/home/Features";
import { Privacy } from "@/app/(landing)/home/Privacy";
import { Testimonials } from "@/app/(landing)/home/Testimonials";
import { Pricing } from "@/app/(app)/premium/Pricing";
import { PricingLazy } from "@/app/(app)/premium/PricingLazy";
import { FAQs } from "@/app/(landing)/home/FAQs";
import { CTA } from "@/app/(landing)/home/CTA";
import { BasicLayout } from "@/components/layouts/BasicLayout";
Expand All @@ -18,7 +17,7 @@ export default function Home() {
<Testimonials />
<Privacy />
<FeaturesHome />
<Pricing className="pb-32" />
<PricingLazy className="pb-32" />
<FAQs />
<CTA />
</BasicLayout>
Expand Down
48 changes: 22 additions & 26 deletions apps/web/app/(landing)/welcome-upgrade/page.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,36 @@
import { Suspense } from "react";
import { CheckCircleIcon } from "lucide-react";
import { Pricing } from "@/app/(app)/premium/Pricing";
import { PricingLazy } from "@/app/(app)/premium/PricingLazy";
import { Footer } from "@/app/(landing)/home/Footer";
import { Loading } from "@/components/Loading";
import { WelcomeUpgradeNav } from "@/app/(landing)/welcome-upgrade/WelcomeUpgradeNav";
import { userCount } from "@/utils/config";

export default function WelcomeUpgradePage() {
return (
<>
<WelcomeUpgradeNav />
<Suspense fallback={<Loading />}>
<Pricing
showSkipUpgrade
header={
<div className="mb-8 flex flex-col items-start">
<div className="mx-auto text-center">
<h2 className="font-cal text-base leading-7 text-blue-600">
Spend 50% less time on email
</h2>
<p className="mt-2 font-cal text-2xl text-gray-900 sm:text-3xl">
Join {userCount} users that use Inbox Zero
<br />
to be more productive!
</p>
</div>
<PricingLazy
showSkipUpgrade
header={
<div className="mb-8 flex flex-col items-start">
<div className="mx-auto text-center">
<h2 className="font-cal text-base leading-7 text-blue-600">
Spend 50% less time on email
</h2>
<p className="mt-2 font-cal text-2xl text-gray-900 sm:text-3xl">
Join {userCount} users that use Inbox Zero
<br />
to be more productive!
</p>
</div>

<div className="mx-auto mt-4 flex flex-col items-start gap-2">
<TrialFeature>100% no-risk trial</TrialFeature>
<TrialFeature>Free for the first 7 days</TrialFeature>
<TrialFeature>Cancel anytime, hassle-free</TrialFeature>
</div>
<div className="mx-auto mt-4 flex flex-col items-start gap-2">
<TrialFeature>100% no-risk trial</TrialFeature>
<TrialFeature>Free for the first 7 days</TrialFeature>
<TrialFeature>Cancel anytime, hassle-free</TrialFeature>
</div>
}
/>
</Suspense>
</div>
}
/>
<Footer />
</>
);
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Metadata } from "next";
import { Suspense } from "react";
import type { Metadata } from "next";
// import { Analytics } from "@vercel/analytics/react";
import { AxiomWebVitals } from "next-axiom";
import { GoogleTagManager } from "@next/third-parties/google";
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.3.16
v1.3.17