Merge pull request #399 from ArnasDon/fix/settings-nav-suspense

fix(settings): wrap useSearchParams pages in Suspense so navigation works in prod
This commit is contained in:
Arnas Donauskas 2026-07-17 15:10:50 +03:00 committed by GitHub
commit b24aa794b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 42 additions and 3 deletions

View File

@ -1501,6 +1501,7 @@
"appearance": "Appearance",
"whatsapp": "WhatsApp",
"templates": "Templates",
"quick-replies": "Quick replies",
"fields": "Fields & tags",
"deals": "Deals & currency",
"members": "Team members",

View File

@ -1,6 +1,6 @@
"use client"
import { useMemo } from "react"
import { Suspense, useMemo } from "react"
import { useSearchParams } from "next/navigation"
import {
@ -11,7 +11,18 @@ import {
import { AUTOMATION_TEMPLATES, type TemplateSlug } from "@/lib/automations/templates"
import type { AutomationStepType, AutomationTriggerType } from "@/types"
// `useSearchParams` requires a Suspense boundary or the production build
// bails to CSR and errors out. Thin wrapper supplies it; the inner
// component reads the `?template=` query string.
export default function NewAutomationPage() {
return (
<Suspense fallback={null}>
<NewAutomationPageInner />
</Suspense>
)
}
function NewAutomationPageInner() {
const params = useSearchParams()
const template = params.get("template") as TemplateSlug | null

View File

@ -1,6 +1,6 @@
"use client";
import { useState, useCallback, useEffect, useRef } from "react";
import { Suspense, useState, useCallback, useEffect, useRef } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { useTranslations } from "next-intl";
import { createClient } from "@/lib/supabase/client";
@ -21,7 +21,18 @@ import { cn } from "@/lib/utils";
// across reloads and sessions (device-scoped, like the theme prefs).
const CONTACT_PANEL_STORAGE_KEY = "wacrm:inbox:contact-panel-open";
// `useSearchParams` (the `?c=<id>` deep link below) requires a Suspense
// boundary or the production build bails to CSR and errors out. Thin
// wrapper supplies it; the inner component holds all the inbox state.
export default function InboxPage() {
return (
<Suspense fallback={null}>
<InboxPageInner />
</Suspense>
);
}
function InboxPageInner() {
const t = useTranslations("Inbox.page");
const router = useRouter();
const searchParams = useSearchParams();

View File

@ -1,6 +1,6 @@
'use client';
import { useMemo, type ReactNode } from 'react';
import { Suspense, useMemo, type ReactNode } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { useTranslations } from 'next-intl';
@ -23,7 +23,23 @@ import {
type SettingsSection,
} from '@/components/settings/settings-sections';
// `useSearchParams` opts this page out of static prerendering unless it
// sits under a Suspense boundary. Without one, the production build hits
// the "missing Suspense with CSR bailout" error and the whole page bails
// to client-side rendering — shipping a settings screen whose rail never
// wires up its click handlers. You land on the section the URL carried
// (the account-menu Settings link points at `?tab=whatsapp`) and can't
// navigate away. Mirror the login/signup split: a thin wrapper supplies
// the boundary; the inner component reads the query string.
export default function SettingsPage() {
return (
<Suspense fallback={null}>
<SettingsPageInner />
</Suspense>
);
}
function SettingsPageInner() {
const router = useRouter();
const searchParams = useSearchParams();
const { defaultCurrency } = useAuth();