mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
fix(settings): wrap useSearchParams pages in Suspense so nav works in prod
The settings page derived its active panel from `useSearchParams()` but
wasn't wrapped in a Suspense boundary. In Next 16 that fails the
production build ("missing Suspense with CSR bailout") and forces the
page to bail to full client-side rendering — shipping a settings screen
whose rail click handlers never wire up. Because the account-menu
Settings link targets `?tab=whatsapp`, users land on the WhatsApp panel
and can't navigate to any other section ("locked on WhatsApp").
Wrap the `useSearchParams` consumer in `<Suspense>` on the three
affected dashboard pages — settings, inbox, automations/new — mirroring
the split login/signup already use. Also add the missing
`Settings.sections.quick-replies` label, which was rendering as a raw
translation key in the settings rail.
Verified: production build now succeeds (previously errored out during
static generation); every settings rail section navigates correctly in a
production build.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
8bbda771ce
commit
8bbbe0a471
@ -1501,6 +1501,7 @@
|
|||||||
"appearance": "Appearance",
|
"appearance": "Appearance",
|
||||||
"whatsapp": "WhatsApp",
|
"whatsapp": "WhatsApp",
|
||||||
"templates": "Templates",
|
"templates": "Templates",
|
||||||
|
"quick-replies": "Quick replies",
|
||||||
"fields": "Fields & tags",
|
"fields": "Fields & tags",
|
||||||
"deals": "Deals & currency",
|
"deals": "Deals & currency",
|
||||||
"members": "Team members",
|
"members": "Team members",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useMemo } from "react"
|
import { Suspense, useMemo } from "react"
|
||||||
import { useSearchParams } from "next/navigation"
|
import { useSearchParams } from "next/navigation"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -11,7 +11,18 @@ import {
|
|||||||
import { AUTOMATION_TEMPLATES, type TemplateSlug } from "@/lib/automations/templates"
|
import { AUTOMATION_TEMPLATES, type TemplateSlug } from "@/lib/automations/templates"
|
||||||
import type { AutomationStepType, AutomationTriggerType } from "@/types"
|
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() {
|
export default function NewAutomationPage() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<NewAutomationPageInner />
|
||||||
|
</Suspense>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function NewAutomationPageInner() {
|
||||||
const params = useSearchParams()
|
const params = useSearchParams()
|
||||||
const template = params.get("template") as TemplateSlug | null
|
const template = params.get("template") as TemplateSlug | null
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useCallback, useEffect, useRef } from "react";
|
import { Suspense, useState, useCallback, useEffect, useRef } from "react";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { createClient } from "@/lib/supabase/client";
|
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).
|
// across reloads and sessions (device-scoped, like the theme prefs).
|
||||||
const CONTACT_PANEL_STORAGE_KEY = "wacrm:inbox:contact-panel-open";
|
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() {
|
export default function InboxPage() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<InboxPageInner />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function InboxPageInner() {
|
||||||
const t = useTranslations("Inbox.page");
|
const t = useTranslations("Inbox.page");
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo, type ReactNode } from 'react';
|
import { Suspense, useMemo, type ReactNode } from 'react';
|
||||||
import { useRouter, useSearchParams } from 'next/navigation';
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
|
||||||
@ -23,7 +23,23 @@ import {
|
|||||||
type SettingsSection,
|
type SettingsSection,
|
||||||
} from '@/components/settings/settings-sections';
|
} 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() {
|
export default function SettingsPage() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<SettingsPageInner />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SettingsPageInner() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const { defaultCurrency } = useAuth();
|
const { defaultCurrency } = useAuth();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user