@php // Node display titles handed to the canvas JS so every label stays server-side // translatable (the builder never hard-codes English in JS). $nodeLabels = [ 'trigger' => __('Trigger'), 'send_message' => __('Send message'), 'send_media' => __('Send media'), 'send_buttons' => __('Send buttons'), 'send_gallery' => __('Send gallery'), 'ask_question' => __('Ask a question'), 'condition' => __('Condition'), 'branch' => __('Branch'), 'add_label' => __('Add label'), 'remove_label' => __('Remove label'), 'set_status' => __('Set status'), 'assign_staff' => __('Assign staff'), 'assign_ai_agent' => __('Assign AI agent'), 'pause_bot' => __('Pause bot'), 'resume_bot' => __('Resume bot'), 'call_webhook' => __('Call webhook'), 'wait' => __('Wait'), 'drip' => __('Drip follow-up'), 'create_client_account' => __('Create client account'), 'welcome_tour' => __('Welcome tour'), '_empty' => __('(empty)'), '_items' => __('items'), '_paths' => __('paths'), '_unsupported' => __('Not supported by the selected channels'), '_fullscreen' => __('Full screen'), '_exit_fullscreen' => __('Exit full screen'), // Multi-output port row labels (CRM-4 fix — see automation-canvas.js // portRowLabel()). `_case` is the fallback prefix for a still-blank // branch path ("Case 1", "Case 2", ...); the `_port_*` keys are the // fixed outcomes of ask_question / condition / create_client_account, // matched 1:1 against NODE_TYPES[type].ports in the canvas JS. '_case' => __('Case'), '_port_captured' => __('Captured'), '_port_gave_up' => __('Gave up'), '_port_yes' => __('Yes'), '_port_no' => __('No'), '_port_created' => __('Created'), '_port_failed' => __('Failed'), ]; // Palette groups (trigger is auto-seeded as the entry node, so it is omitted). $palette = [ __('Messaging') => ['send_message', 'send_media', 'send_gallery', 'send_buttons', 'ask_question'], __('Flow') => ['condition', 'branch', 'wait', 'drip'], __('Actions') => ['add_label', 'remove_label', 'set_status', 'assign_ai_agent', 'assign_staff', 'pause_bot', 'resume_bot', 'create_client_account', 'call_webhook'], ]; // Interpolation tokens must live in PHP, NOT inside a Blade {{ }} echo — a // literal {{ }} nested in an echo breaks the compiler (documented pitfall). $tokenContactName = '{{contact.name|there}}'; $tokenAnswersEmail = '{{answers.email}}'; $phSendMessage = __('Hi :token!', ['token' => $tokenContactName]); $phAskHint = __('Use it later with :token', ['token' => $tokenAnswersEmail]); // Trigger-event catalogue for the Trigger node's event picker + list badge // (six events; the three "event" kinds fire from UI actions, §8). $rfTriggers = []; foreach ((array) config('crm.automation_triggers', []) as $val => $meta) { $rfTriggers[] = ['value' => $val, 'label' => __($meta['label']), 'needs_keyword' => (bool) ($meta['needs_keyword'] ?? false)]; } // Merge-tag catalogue → the clickable chips rendered in every text panel. The // token strings carry literal {{ }} and MUST stay in PHP (see pitfall above); // they reach the canvas only through @js(), never a Blade echo. $rfVariables = array_map( fn ($v) => ['token' => $v['token'], 'label' => __($v['label']), 'example' => $v['example']], (array) config('crm.automation_variables', []), ); // Targetable channels (no support) for the Trigger node's channel scope boxes. $rfChannelMeta = []; foreach ((array) config('crm.channels', []) as $type => $meta) { if ($type !== 'support') { $rfChannelMeta[] = ['type' => $type, 'label' => $meta['label'], 'color' => $meta['color']]; } } // Static help text (safe to echo — echoing a variable whose VALUE contains // {{ }} is fine; only literal {{ }} in template text breaks the compiler). $rfVarHelp = __(config('crm.automation_personalization_example', '')); $rfCapNote = __(config('crm.automation_channel_note', '')); @endphp
@if (! $showEditor) {{-- ============================ LIST ============================ --}}

{{ __('Automations') }}

{{ __('Build visual flows that welcome, capture and convert on every channel.') }}

@if ($automations->isEmpty()) @else
@foreach ($automations as $a) @php $aChannels = (array) ($a->trigger_data['channels'] ?? []); @endphp @endforeach
{{ __('Automation') }} {{ __('Trigger') }} {{ __('Channels') }} {{ __('Runs') }} {{ __('Status') }} {{ __('Actions') }}
{{ $a->name }} {{ __(config("crm.automation_triggers.{$a->trigger_type}.label", ucfirst(str_replace('_', ' ', $a->trigger_type)))) }} @if (empty($aChannels)) {{ __('All channels') }} @else @foreach (array_slice($aChannels, 0, 5) as $ch) @endforeach @endif {{ $a->runs_count }}
@endif
{{-- Template gallery — browse BY social network (owner ask). Each network tab shows the templates that run on it, still sectioned by category; the "All channels" tab holds the flows that run everywhere. Capability-honest: a buttons flow only targets button-capable networks, so it can never surface under a network that cannot render it. --}} @php // Icon + accent per category so each section reads at a glance. $catMeta = [ 'marketing' => ['icon' => 'megaphone', 'color' => '#DB2777'], 'sales' => ['icon' => 'shopping-cart', 'color' => '#16A34A'], 'support' => ['icon' => 'life-buoy', 'color' => '#0EA5E9'], ]; // Open on the first available tab (galleryNetworks() puts "All channels" first). $networkKeys = array_keys($galleryNetworks); $defaultNet = $networkKeys[0] ?? 'all'; @endphp

{{ __('Browse ready-made flows by the network they run on. Flows that use interactive buttons only appear under networks that support them.') }}

{{-- Network tab bar --}}
@foreach ($galleryNetworks as $net => $meta) @endforeach
{{-- Per-network panels: one x-show block per network, each still sectioned by category so the commercial grouping keeps working. --}} @foreach ($networkTemplates as $net => $netTemplates)
@foreach ($categoryLabels as $cat => $catLabel) @php $items = array_filter($netTemplates, fn ($t) => ($t['category'] ?? '') === $cat); @endphp @if (! empty($items))

{{ $catLabel }}

@foreach ($items as $key => $tpl) @endforeach
@endif @endforeach
@endforeach
@else {{-- ============================ EDITOR ============================ --}}

{{ $editingId ? __('Edit automation') : __('New automation') }}

{{-- Fires a window event the canvas listens for; it serialises the graph and calls $wire.saveFlow(json) for server validation. --}}
{{-- Automation-level header. Name lives here; the trigger event, keyword and channel scope moved INTO the Trigger node on the canvas, so there is one clear place to configure how a flow starts. --}}
@error('name')

{{ $message }}

@enderror

{{ __('Select the Trigger node on the canvas to set the event, keyword and channels.') }}

@error('trigger_type')

{{ $message }}

@enderror @error('keyword')

{{ $message }}

@enderror @error('flowData')

{{ $message }}

@enderror
{{-- The canvas subtree. wire:ignore keeps Livewire out of Drawflow's managed DOM; wire:key on editorNonce re-mounts a clean editor when a different automation is opened, so the graph never leaks between edits. --}}
{{-- Palette --}}
@foreach ($palette as $group => $types)

{{ $group }}

@foreach ($types as $type) {{-- Channel-capability gating: a node whose required capability (buttons/media/gallery) is not supported by ALL targeted channels is grayed + non-draggable, with a tooltip. Updates live as the channel checkboxes change (nodeAvailable reads the reactive targetChannels). --}} @endforeach @endforeach
{{-- Canvas --}}
{{-- The zoom level doubles as the reset control: reads instantly as a percentage (no longer a fullscreen-lookalike icon). --}} {{-- Full screen toggle: maximises the whole editor via the Fullscreen API (CSS fixed-inset fallback), and re-measures the canvas. --}}
{{-- Properties --}}

{{ __('Select a node to edit it, or drag one from the palette.') }}

{{-- trigger — the flow's entry point: event + keyword + channel scope. This is the single place to configure how a flow starts; the channel boxes drive the palette gray-out. --}} {{-- send_message --}} {{-- send_media --}} {{-- send_buttons --}} {{-- send_gallery --}} {{-- ask_question --}} {{-- condition --}} {{-- branch --}} {{-- set_status --}} {{-- add_label / remove_label --}} {{-- assign_ai_agent --}} {{-- assign_staff --}} {{-- wait / drip --}} {{-- call_webhook --}} {{-- create_client_account --}} {{-- info-only nodes (trigger now has its own panel above) --}}
@endif