@php $isEdit = isset($package) && $package; $title = $isEdit ? 'Edit package' : 'Create package'; $action = $isEdit ? route('admin.packages.update', $package->id) : route('admin.packages.store'); $limitLabels = [ 'device_limit' => 'Devices', 'monthly_messages_limit' => 'Messages / month', 'contacts_limit' => 'Contacts', 'broadcast_limit' => 'Broadcasts', 'template_limit' => 'Templates', 'groups_limit' => 'Groups', 'campaign_messages_limit' => 'Campaign messages', 'automation_messages_limit' => 'Automation messages', 'broadcast_size_limit' => 'Broadcast size', 'total_campaigns_limit' => 'Total campaigns', 'active_campaign_limit' => 'Active campaigns', 'user_seat_limit' => 'Team seats', 'tags_limit' => 'Tags', 'flow_limit' => 'Flows', 'flow_steps_limit' => 'Steps per flow', 'autoreply_limit' => 'Keyword auto-replies', 'chatbot_limit' => 'Chatbots', 'scheduled_campaign_limit' => 'Scheduled campaigns', 'daily_media_size_allowance' => 'Daily media MB', 'workspaces_per_owner_limit' => 'Workspaces per owner', 'routing_rules_limit' => 'Routing rules', 'drip_campaigns_limit' => 'Drip campaigns', 'appointments_limit' => 'Appointments / month', 'ai_agents_limit' => 'AI agents', 'saved_replies_limit' => 'Quick replies', 'webhooks_limit' => 'Outbound webhooks', 'ai_token_limit_monthly' => 'AI tokens / month', // Sprint 9.5 caps. 'waba_calling_minutes_monthly' => 'WABA calling minutes / mo', 'ai_voice_minutes_monthly' => 'AI voice minutes / mo', 'ai_chat_messages_monthly' => 'AI chat messages / mo', 'ai_training_sources_limit' => 'AI training sources', 'chatbot_widgets_limit' => 'Chatbot website widgets', 'storefronts_limit' => 'WA storefronts', 'sla_policies_limit' => 'SLA policies', 'translation_chars_monthly' => 'Translation chars / mo', ]; $featureLabels = [ 'autoreply' => 'Auto-reply system', 'bulkmessage' => 'Bulk messaging', 'schedulemessage' => 'Scheduled messages', 'ads' => 'Meta Ads integration', 'campaign' => 'Campaigns', 'autoflow' => 'Flow builder', 'broadcast' => 'Broadcasts', 'chatgpt_suggestion' => 'AI reply suggestions', 'template' => 'Templates', 'access_carousel_templates' => 'Carousel templates', 'role_based_permissions' => 'Role-based permissions', 'access_drip_campaigns' => 'Drip campaigns', 'access_ctwa' => 'Click-to-WhatsApp ads', 'access_analytics' => 'Analytics dashboard', 'remove_branding' => 'Remove ' . \App\Models\SystemSetting::get('app_name', config('app.name', 'WaDesk')) . ' branding', 'integration_shopify' => 'Shopify integration', 'integration_woocommerce' => 'WooCommerce integration', 'integration_hubspot' => 'HubSpot integration', 'integration_google_calendar' => 'Google Calendar', 'integration_google_sheets' => 'Google Sheets', 'access_kanban_view' => 'Kanban view', 'access_appointment_booking' => 'Appointment booking', 'access_edit_messages' => 'Edit sent messages', 'access_internal_notes' => 'Internal notes', 'access_message_reactions' => 'Message reactions', 'access_routing_rules' => 'Routing rules', 'access_business_hours' => 'Business hours', 'access_team_performance' => 'Team performance', 'access_outbound_webhooks' => 'Outbound webhooks', 'access_keyword_replies' => 'Keyword auto-replies', 'access_ai_agents' => 'AI agents', 'allow_byok_ai_keys' => 'Bring your own AI keys', 'multipledevice' => 'Multi-device sending', 'file_type_restrictions' => 'File-type upload restrictions', // Sprint 9.5 toggles. 'access_waba_calling' => 'WhatsApp Cloud-API voice calling', 'access_call_recording' => 'Call recording', 'access_ai_voice_agent' => 'AI voice agent (answer calls)', 'access_ai_chat_assistant' => 'AI chat assistant (text)', 'access_ai_training' => 'AI training sources', 'access_ai_generate' => 'Inline "Generate with AI" buttons', 'access_wa_storefront' => 'WhatsApp Storefront / catalog', 'access_flows_commerce' => 'Commerce-aware flows', 'access_chatbot_widgets' => 'Chatbot website widgets', 'access_sla_policies' => 'SLA policies', 'access_translation' => 'Multilingual auto-translation', 'access_data_residency' => 'Data residency (EU/local) drivers', ]; // Logical limit groups (mapped to the columns the form ships with). $limitGroups = [ 'Messaging caps' => [ 'monthly_messages_limit', 'broadcast_limit', 'broadcast_size_limit', 'campaign_messages_limit', 'automation_messages_limit', 'scheduled_campaign_limit', 'total_campaigns_limit', 'active_campaign_limit', 'daily_media_size_allowance', ], 'Workspace caps' => [ 'device_limit', 'user_seat_limit', 'contacts_limit', 'groups_limit', 'workspaces_per_owner_limit', 'tags_limit', ], 'Content caps' => [ 'template_limit', 'flow_limit', 'flow_steps_limit', 'autoreply_limit', 'chatbot_limit', 'saved_replies_limit', ], 'AI & voice caps' => [ 'waba_calling_minutes_monthly', 'ai_voice_minutes_monthly', 'ai_chat_messages_monthly', 'ai_agents_limit', 'ai_training_sources_limit', 'ai_token_limit_monthly', ], 'Commerce & SLA' => [ 'storefronts_limit', 'chatbot_widgets_limit', 'sla_policies_limit', 'translation_chars_monthly', 'drip_campaigns_limit', 'appointments_limit', ], 'Other caps' => ['webhooks_limit', 'routing_rules_limit'], ]; // Logical feature groups. $featureGroups = [ 'Messaging' => [ 'autoreply', 'bulkmessage', 'schedulemessage', 'campaign', 'autoflow', 'broadcast', 'template', 'access_carousel_templates', 'access_drip_campaigns', 'access_keyword_replies', 'access_edit_messages', 'access_message_reactions', ], 'Inbox & team' => [ 'access_internal_notes', 'access_routing_rules', 'access_business_hours', 'access_team_performance', 'access_kanban_view', 'access_appointment_booking', 'access_sla_policies', 'role_based_permissions', ], 'AI & calling' => [ 'access_waba_calling', 'access_call_recording', 'access_ai_voice_agent', 'access_ai_chat_assistant', 'access_ai_training', 'access_ai_generate', 'access_ai_agents', 'allow_byok_ai_keys', 'chatgpt_suggestion', ], 'Commerce' => [ 'access_wa_storefront', 'access_flows_commerce', 'access_chatbot_widgets', 'integration_shopify', 'integration_woocommerce', ], 'Integrations' => [ 'integration_hubspot', 'integration_google_calendar', 'integration_google_sheets', 'access_outbound_webhooks', ], 'Advanced' => [ 'ads', 'access_ctwa', 'access_analytics', 'multipledevice', 'file_type_restrictions', 'access_translation', 'access_data_residency', 'remove_branding', ], ]; $val = function ($field, $default = null) use ($package) { return old($field, $package->{$field} ?? $default); }; @endphp
{{ __('Admin') }} {{ __('Packages') }} {{ $isEdit ? 'Edit' : 'New' }}
{{ __('Step') }} 1 / 4 {{ __('Cancel') }}
Admin · Packages · {{ $isEdit ? 'Edit' : 'New' }}

{{ $isEdit ? 'Edit' : 'Create a' }} {{ $isEdit ? 'package' : 'package' }}

{{ __("Set pricing, numeric limits, feature toggles, and display options. Empty limit field = unlimited. Unchecked toggle = workspaces on this plan can't use that feature.") }}

@if (session('success'))
{{ session('success') }}
@endif @if (session('error'))
{{ session('error') }}
@endif @if ($errors->any())
{{ __('Please fix the following:') }}
    @foreach ($errors->all() as $e)
  • {{ $e }}
  • @endforeach
@endif
@csrf @if ($isEdit) @method('PATCH') @endif
{{-- Stepper bar --}}
@php $steps = ['Basics', 'Limits', 'Features', 'Display & review']; @endphp @foreach ($steps as $i => $label)
{{ $loop->iteration }} {{ $label }} @if (!$loop->last) @endif
@endforeach
{{-- STEP 1 — Basics --}}
01 {{ __('Plan basics') }} {{ __('required') }}
0 = free. Set "Free plan" toggle below.
e.g. 1 month = monthly recurring, 1 year = annual.
@php $basicsFlags = [ 'free' => ['Free plan', 'No charge, no recurring billing'], 'lifetime' => ['Lifetime', 'One-time payment, no renewal'], 'status' => ['Active', 'Visible on the public pricing page'], 'is_default' => [ 'Default for signups', 'New workspaces get this plan automatically', ], 'is_highlighted' => ['Highlight as popular', 'Adds "Most popular" badge'], 'is_custom_quote' => ['Custom quote', 'Hides price, shows "Contact sales"'], ]; @endphp @foreach ($basicsFlags as $name => $meta) @endforeach
{{-- STEP 2 — Limits --}} {{-- STEP 3 — Features --}} {{-- STEP 4 — Display + Review --}}