mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
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>
102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
"use client"
|
|
|
|
import { Suspense, useMemo } from "react"
|
|
import { useSearchParams } from "next/navigation"
|
|
|
|
import {
|
|
AutomationBuilder,
|
|
type BuilderInitial,
|
|
type BuilderStep,
|
|
} from "@/components/automations/automation-builder"
|
|
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
|
|
|
|
const initial: BuilderInitial = useMemo(() => {
|
|
if (template && AUTOMATION_TEMPLATES[template]) {
|
|
const t = AUTOMATION_TEMPLATES[template]
|
|
const steps = expandFromSeeds(
|
|
t.steps.map((seed, idx) => ({
|
|
index: idx,
|
|
step_type: seed.step_type,
|
|
step_config: seed.step_config as Record<string, unknown>,
|
|
branch: seed.branch ?? null,
|
|
parent_index: seed.parent_index ?? null,
|
|
})),
|
|
)
|
|
return {
|
|
name: t.name,
|
|
description: t.description,
|
|
trigger_type: t.trigger_type,
|
|
trigger_config: t.trigger_config as Record<string, unknown>,
|
|
is_active: false,
|
|
steps,
|
|
}
|
|
}
|
|
return {
|
|
name: "",
|
|
description: "",
|
|
trigger_type: "new_message_received" as AutomationTriggerType,
|
|
trigger_config: {},
|
|
is_active: false,
|
|
steps: [],
|
|
}
|
|
}, [template])
|
|
|
|
return <AutomationBuilder initial={initial} />
|
|
}
|
|
|
|
interface SeedRow {
|
|
index: number
|
|
step_type: AutomationStepType
|
|
step_config: Record<string, unknown>
|
|
branch: "yes" | "no" | null
|
|
parent_index: number | null
|
|
}
|
|
|
|
function uid(): string {
|
|
return (
|
|
"c_" +
|
|
(typeof crypto !== "undefined" && "randomUUID" in crypto
|
|
? crypto.randomUUID()
|
|
: Math.random().toString(36).slice(2) + Date.now().toString(36))
|
|
)
|
|
}
|
|
|
|
/** Template seeds are flat with parent_index references. Expand into the
|
|
* builder's nested tree, preserving order within each scope. */
|
|
function expandFromSeeds(rows: SeedRow[]): BuilderStep[] {
|
|
const nodes: BuilderStep[] = rows.map((r) => ({
|
|
cid: uid(),
|
|
step_type: r.step_type,
|
|
step_config: r.step_config,
|
|
branches:
|
|
r.step_type === "condition" ? { yes: [], no: [] } : undefined,
|
|
}))
|
|
const roots: BuilderStep[] = []
|
|
rows.forEach((r, i) => {
|
|
if (r.parent_index == null) {
|
|
roots.push(nodes[i])
|
|
return
|
|
}
|
|
const parent = nodes[r.parent_index]
|
|
if (!parent.branches) parent.branches = { yes: [], no: [] }
|
|
parent.branches[r.branch ?? "yes"].push(nodes[i])
|
|
})
|
|
return roots
|
|
}
|