mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
PR #132 (color themes) only tokenized the high-visibility chrome. Inbox / contacts / pipelines / broadcasts / automations / auth / settings sub-forms still had ~150 hard-coded `violet-*` classes across ~32 files, so picking a non-violet theme felt half-broken — sidebar and header changed colour, but message bubbles, deal cards, and the broadcast wizard all stayed violet. This is the mechanical follow-up: replace every `violet-N(/N)?` with `primary(/N)?` so the theme picker themes the whole app. Two non-trivial swaps inside the pass: - `text-white` on a `bg-primary` button → `text-primary-foreground`. Emerald and Amber define a *dark* `--primary-foreground` because their primaries are bright; `text-white` over those would tank contrast. - `bg-primary hover:bg-primary` (hover identical to base — original code had this latent bug from `hover:bg-violet-500`) → adds `/90` on hover so the lift is visible. Test update: - `broadcast-status.test.ts` asserted shade numbers (`bg-X-N/10`). Relaxed the regex to also accept token form (`bg-X/10`) since brand-accent status badges now ride the active theme. Files touched: 49. Lint clean (existing warnings only), 173/173 tests, typecheck + build green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
"use client"
|
|
|
|
import { use, useEffect, useState } from "react"
|
|
import { useRouter } from "next/navigation"
|
|
import { Loader2 } from "lucide-react"
|
|
|
|
import {
|
|
AutomationBuilder,
|
|
fromServerSteps,
|
|
type BuilderInitial,
|
|
type ServerStepNode,
|
|
} from "@/components/automations/automation-builder"
|
|
import type { AutomationTriggerType } from "@/types"
|
|
|
|
export default function EditAutomationPage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ id: string }>
|
|
}) {
|
|
const { id } = use(params)
|
|
const router = useRouter()
|
|
const [initial, setInitial] = useState<BuilderInitial | null>(null)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
useEffect(() => {
|
|
let cancelled = false
|
|
async function load() {
|
|
const res = await fetch(`/api/automations/${id}`)
|
|
if (!res.ok) {
|
|
if (!cancelled) setError(`Failed to load (${res.status})`)
|
|
return
|
|
}
|
|
const body = await res.json()
|
|
if (cancelled) return
|
|
setInitial({
|
|
id: body.automation.id,
|
|
name: body.automation.name ?? "",
|
|
description: body.automation.description ?? "",
|
|
trigger_type: body.automation.trigger_type as AutomationTriggerType,
|
|
trigger_config: body.automation.trigger_config ?? {},
|
|
is_active: !!body.automation.is_active,
|
|
steps: fromServerSteps((body.steps ?? []) as ServerStepNode[]),
|
|
})
|
|
}
|
|
load()
|
|
return () => {
|
|
cancelled = true
|
|
}
|
|
}, [id])
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="flex h-screen flex-col items-center justify-center gap-3">
|
|
<p className="text-sm text-red-400">{error}</p>
|
|
<button
|
|
onClick={() => router.push("/automations")}
|
|
className="text-sm text-primary hover:text-primary/80"
|
|
>
|
|
Back to Automations
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (!initial) {
|
|
return (
|
|
<div className="flex h-screen items-center justify-center">
|
|
<Loader2 className="h-6 w-6 animate-spin text-primary" />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return <AutomationBuilder initial={initial} />
|
|
}
|