From 3207b7e5689ca620c66e083fbeae0a53d2297d8b Mon Sep 17 00:00:00 2001 From: manoel freitas Date: Thu, 13 Aug 2026 23:30:58 -0300 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20registrar=20Modalidade=20vs=20Servi?= =?UTF-8?q?ce=20no=20modelo=20de=20dom=C3=ADnio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit O visitante vê modalidades de casamento; services permanece vertente. Preço e limites ficam fora do registro público. Co-authored-by: Cursor --- PRODUCT.md | 2 +- SPEC.md | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/PRODUCT.md b/PRODUCT.md index b850b0c..d85a276 100644 --- a/PRODUCT.md +++ b/PRODUCT.md @@ -37,7 +37,7 @@ No lançamento, o site público premium e o CMS interno formam a superfície ent ## Operating Context - Atuação em São Paulo, capital. -- Serviços: casamentos, eventos corporativos e celebrações. +- Serviços: casamentos, eventos corporativos e celebrações. No site, casamento aparece como três **modalidades** (Essenza, Conduzione, Grand Jour); preço e limites comerciais ficam na proposta, não na página. - Operação realizada por assessora principal e equipe pequena. - Jornada de lançamento: descoberta no site, briefing por e-mail e contato comercial fora da plataforma. - Jornada futura prevista: qualificação do lead, pipeline comercial, conversão em evento, checklist, fornecedores, orçamento, pagamentos manuais e documentos. diff --git a/SPEC.md b/SPEC.md index 7e977e2..8243689 100644 --- a/SPEC.md +++ b/SPEC.md @@ -1254,6 +1254,12 @@ Auditoria não precisa ser um event sourcing. Registrar apenas operações crít | Finance | Orçamento e pagamentos manuais | | Identity | Usuários, acesso e auditoria | +Vocabulário público vs persistência (Marketing): + +- **Modalidade** é o nome público de cada oferta de acompanhamento de casamento. O visitante vê o nome próprio (Essenza, Conduzione, Grand Jour) e a tag de momento (Completa, Parcial, Final). Persistida em `wedding_packages`. +- **Vertente** é o contexto da marca (Casamentos vs Corporate). A tabela `services` descreve vertentes do catálogo, não as três modalidades. +- **Pacote**, no sentido de SKU com preço e limites operacionais, não é superfície pública. Preço, equipe no dia, teto de fornecedores, quilometragem e ferramentas de terceiros (incluindo gestão de convidados) ficam na proposta, não no registro público da modalidade. + ### 8.2 Tabelas obrigatórias #### `users` @@ -1314,6 +1320,27 @@ Singleton: - timestamps; - soft delete opcional somente se recuperação for necessária. +#### `wedding_packages` + +Modalidades públicas de casamento (não confundir com `services`): + +- `id`; +- `name`; +- `slug` unique; +- `level` (rótulo de momento, ex. `01 / COMPLETA`); +- `tag` nullable (ex. Assessoria completa); +- `subtitle` nullable; +- `summary`; +- `scope_items` jsonb (bullets de conceito nos cards); +- `cta_label`; +- `compare_heading` nullable; +- `compare_summary` nullable; +- campos editoriais da página `/pacotes/{slug}` (eyebrow, título, hero, benefícios, incluso em alto nível, audiência, CTA final, meta) — todos opcionais salvo o que a publicação exigir; +- `sort_order` integer indexed; +- `published_at` timestamp nullable indexed; +- timestamps; +- **sem** colunas de preço, centavos, equipe, limites de fornecedores/convidados/km ou ferramentas de terceiros. + #### `portfolio_cases` - `id`; -- 2.49.1 From 220143390e20db2dc05363b61a85fcfb2319e595 Mon Sep 17 00:00:00 2001 From: manoel freitas Date: Thu, 13 Aug 2026 23:39:29 -0300 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20alinhar=20copy=20das=20modalidades?= =?UTF-8?q?=20=C3=A0=20Apresenta=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cards e páginas /pacotes passam a usar o texto conceitual oficial, sem preço, VIP ou limites comerciais. Co-authored-by: Cursor --- database/seeders/WeddingPackagesSeeder.php | 171 +++++++++--------- .../Feature/Marketing/WeddingPackageTest.php | 27 +++ 2 files changed, 115 insertions(+), 83 deletions(-) diff --git a/database/seeders/WeddingPackagesSeeder.php b/database/seeders/WeddingPackagesSeeder.php index 24b3846..1e5f9e1 100644 --- a/database/seeders/WeddingPackagesSeeder.php +++ b/database/seeders/WeddingPackagesSeeder.php @@ -9,11 +9,10 @@ use Illuminate\Database\Seeder; use Illuminate\Support\Carbon; /** - * Wedding package modalities shown on the home page (03 — Amare Casamentos) - * and the services page. Copy is approved from the structural model preview - * (preview(2).html) and remains editable via the Filament resource. Detail - * copy follows the complete-assessoria preview - * (amare-assessoria-completa.html) adapted to each modality. + * Wedding package modalities shown on the home page, services page and + * `/pacotes/{slug}`. Public copy follows "Apresentação dos serviços Amare" + * (conceito e momento). Commercial limits, price and third-party tools stay + * off this seeder and off the public site. */ class WeddingPackagesSeeder extends Seeder { @@ -27,141 +26,147 @@ class WeddingPackagesSeeder extends Seeder 'slug' => 'essenza', 'level' => '01 / COMPLETA', 'tag' => 'Assessoria completa', - 'subtitle' => 'Do planejamento ao grande dia.', - 'summary' => 'Para casais que desejam contar com a Amare desde o início ou ainda estão estruturando etapas importantes.', + 'subtitle' => 'Do primeiro planejamento ao grande dia.', + 'summary' => 'Ideal para casais que desejam contar com a Amare desde o início da organização ou que ainda estão estruturando etapas importantes do casamento.', 'scope_items' => [ - 'Estruturação do planejamento', - 'Cronogramas, prazos e prioridades', - 'Orientação e gestão de fornecedores', - 'Alinhamento entre os envolvidos', - 'Coordenação da execução', + 'Estruturação e acompanhamento do planejamento', + 'Organização de cronogramas, prazos e prioridades', + 'Orientação na contratação e gestão de fornecedores', + 'Acompanhamento das etapas do projeto', + 'Organização e conferência de contratos e informações', + 'Alinhamento entre casal, fornecedores e demais envolvidos', + 'Construção do cronograma do grande dia', + 'Coordenação e acompanhamento da execução do evento', ], 'cta_label' => 'Quero conhecer a Essenza', 'compare_heading' => 'Começar com a Amare', - 'compare_summary' => 'Acompanhamento mais amplo ao longo do planejamento.', + 'compare_summary' => 'Acompanhamento do primeiro planejamento ao grande dia.', 'sort_order' => 1, 'eyebrow' => 'Assessoria', 'title_line' => 'Assessoria', 'title_emphasis' => 'Completa', - 'hero_lead' => 'Do planejamento ao grande dia, com calma, precisão e cuidado.', + 'hero_lead' => 'A assessoria completa acompanha o projeto de forma estratégica e próxima, desde a construção do planejamento até a execução do evento.', 'benefits' => [ - ['icon_key' => 'calendar', 'label' => 'Organização integral'], - ['icon_key' => 'checklist', 'label' => 'Planejamento personalizado'], - ['icon_key' => 'users', 'label' => 'Fornecedores selecionados'], - ['icon_key' => 'heart', 'label' => 'Experiência leve e inesquecível'], + ['icon_key' => 'calendar', 'label' => 'Planejamento organizado'], + ['icon_key' => 'checklist', 'label' => 'Decisões mais seguras'], + ['icon_key' => 'users', 'label' => 'Fornecedores alinhados'], + ['icon_key' => 'heart', 'label' => 'Grande dia com leveza'], ], 'included_items' => [ - ['icon_key' => 'heart', 'title' => 'Escuta e briefing', 'description' => 'Cada casal é único; começamos por ouvir.'], - ['icon_key' => 'checklist', 'title' => 'Planejamento completo', 'description' => 'Cada etapa mapeada com clareza.'], - ['icon_key' => 'map', 'title' => 'Gestão de fornecedores', 'description' => 'Contatos e prazos sob cuidado.'], - ['icon_key' => 'calendar', 'title' => 'Acompanhamento contínuo', 'description' => 'Perto do casal em cada decisão.'], - ['icon_key' => 'spark', 'title' => 'Produção e logística', 'description' => 'Dia a dia do evento organizado nos detalhes.'], - ['icon_key' => 'users', 'title' => 'Dia do evento', 'description' => 'Coordenação total para o casal viver o momento.'], + ['icon_key' => 'checklist', 'title' => 'Estruturação do planejamento', 'description' => 'Organização do projeto desde o início, no ritmo do casal.'], + ['icon_key' => 'calendar', 'title' => 'Cronogramas e prioridades', 'description' => 'Prazos e etapas visíveis para decidir com calma.'], + ['icon_key' => 'map', 'title' => 'Contratação e gestão de fornecedores', 'description' => 'Orientação e acompanhamento de quem entra no projeto.'], + ['icon_key' => 'users', 'title' => 'Alinhamento entre envolvidos', 'description' => 'Casal, fornecedores e demais partes na mesma conversa.'], + ['icon_key' => 'spark', 'title' => 'Contratos e informações', 'description' => 'Conferência do que foi combinado antes do grande dia.'], + ['icon_key' => 'heart', 'title' => 'Coordenação da execução', 'description' => 'Acompanhamento do evento para o casal viver o momento.'], ], - 'audience_heading' => 'Para quem é este pacote', - 'audience_intro' => 'Para quem quer uma assessoria completa, do início ao fim.', + 'audience_heading' => 'Para quem é esta modalidade', + 'audience_intro' => 'Para quem deseja ter ao lado uma profissional conduzindo o processo como um todo, com organização, estratégia e tranquilidade.', 'audience_points' => [ - 'Casamentos', - 'Aniversários', - 'Eventos sociais e celebrações', - 'Eventos corporativos', + 'Casais no início da organização', + 'Quem ainda está estruturando etapas importantes', + 'Quem quer acompanhamento do planejamento à execução', ], - 'final_cta_heading' => 'Pronta para começar?', - 'final_cta_body' => 'Conte seu evento para a Amare e receba uma proposta.', + 'final_cta_heading' => 'Vamos nos conhecer?', + 'final_cta_body' => 'Antes de definir qualquer caminho, queremos conhecer vocês. Basta entrar em contato para uma conversa.', ], [ 'name' => 'Conduzione', 'slug' => 'conduzione', 'level' => '02 / PARCIAL', 'tag' => 'Assessoria parcial', - 'subtitle' => 'Para quem já começou e quer seguir acompanhado.', - 'summary' => 'Para casais que já tomaram decisões e contrataram parte dos fornecedores, mas precisam estruturar o que falta.', + 'subtitle' => 'Para quem já começou, mas quer seguir acompanhado.', + 'summary' => 'Indicada para casais que já iniciaram o planejamento e possuem parte dos fornecedores ou decisões definidas, mas desejam organizar o que falta e conduzir as próximas etapas.', 'scope_items' => [ - 'Diagnóstico do planejamento existente', - 'Organização das pendências', - 'Gestão dos fornecedores contratados', - 'Orientação para próximas decisões', - 'Coordenação da execução', + 'Diagnóstico do planejamento já realizado', + 'Organização das etapas pendentes', + 'Gestão e acompanhamento dos fornecedores já contratados', + 'Orientação sobre as próximas decisões', + 'Acompanhamento de prazos e informações', + 'Comunicação e alinhamento com fornecedores', + 'Organização do cronograma do evento', + 'Coordenação da execução no grande dia', ], 'cta_label' => 'Quero conhecer a Conduzione', 'compare_heading' => 'Trazer a Amare para o caminho', - 'compare_summary' => 'O planejamento existe, mas ainda há decisões e gestão pela frente.', + 'compare_summary' => 'O planejamento existe; a Amare organiza o que falta e conduz as próximas etapas.', 'sort_order' => 2, 'eyebrow' => 'Assessoria', 'title_line' => 'Assessoria', 'title_emphasis' => 'Parcial', - 'hero_lead' => 'Para retomar o planejamento, organizar o que falta e seguir com acompanhamento profissional.', + 'hero_lead' => 'A Amare entra no momento em que vocês estão, compreende o que já foi construído e assume a gestão das etapas necessárias dentro do planejamento.', 'benefits' => [ - ['icon_key' => 'checklist', 'label' => 'Diagnóstico completo'], - ['icon_key' => 'calendar', 'label' => 'Organização integral'], - ['icon_key' => 'users', 'label' => 'Fornecedores selecionados'], - ['icon_key' => 'heart', 'label' => 'Experiência leve e inesquecível'], + ['icon_key' => 'checklist', 'label' => 'Diagnóstico do que já existe'], + ['icon_key' => 'calendar', 'label' => 'Pendências organizadas'], + ['icon_key' => 'users', 'label' => 'Fornecedores acompanhados'], + ['icon_key' => 'heart', 'label' => 'Próximas decisões com clareza'], ], 'included_items' => [ - ['icon_key' => 'checklist', 'title' => 'Diagnóstico do planejamento', 'description' => 'Um olhar profissional sobre o que já existe.'], - ['icon_key' => 'calendar', 'title' => 'Organização das pendências', 'description' => 'Prioridades claras, etapa a etapa.'], - ['icon_key' => 'map', 'title' => 'Gestão de fornecedores', 'description' => 'Contatos e prazos sob cuidado.'], - ['icon_key' => 'spark', 'title' => 'Gestão dos próximos passos', 'description' => 'Um plano para chegar tranquilo ao grande dia.'], - ['icon_key' => 'users', 'title' => 'Acompanhamento contínuo', 'description' => 'Perto do casal em cada decisão.'], - ['icon_key' => 'heart', 'title' => 'Dia do evento', 'description' => 'Coordenação total para o casal viver o momento.'], + ['icon_key' => 'checklist', 'title' => 'Diagnóstico do planejamento', 'description' => 'Um olhar profissional sobre o que o casal já construiu.'], + ['icon_key' => 'calendar', 'title' => 'Etapas pendentes', 'description' => 'O que falta ganha ordem, prazo e prioridade.'], + ['icon_key' => 'map', 'title' => 'Fornecedores já contratados', 'description' => 'Gestão e comunicação com quem já está no projeto.'], + ['icon_key' => 'spark', 'title' => 'Próximas decisões', 'description' => 'Orientação para seguir sem retrabalho.'], + ['icon_key' => 'users', 'title' => 'Cronograma do evento', 'description' => 'A operação do grande dia começa a ficar visível.'], + ['icon_key' => 'heart', 'title' => 'Coordenação no grande dia', 'description' => 'Execução acompanhada para o casal viver o momento.'], ], - 'audience_heading' => 'Para quem é este pacote', - 'audience_intro' => 'Para quem já começou a planejar e quer retomar as rédeas com acompanhamento profissional.', + 'audience_heading' => 'Para quem é esta modalidade', + 'audience_intro' => 'Para quem já deu os primeiros passos, mas deseja seguir com mais segurança, organização e tranquilidade.', 'audience_points' => [ - 'Casamentos em andamento', - 'Casais com pouco tempo disponível', - 'Quem precisa priorizar pendências', - 'Quem busca fornecedores confiáveis', + 'Casais que já iniciaram o planejamento', + 'Quem já tem parte dos fornecedores ou decisões definidas', + 'Quem quer condução profissional nas etapas que faltam', ], - 'final_cta_heading' => 'Pronta para retomar?', - 'final_cta_body' => 'Conte onde seu planejamento está e receba uma proposta.', + 'final_cta_heading' => 'Vamos organizar o que falta?', + 'final_cta_body' => 'Conte onde o planejamento está. A Amare entra nesse momento e conduz as próximas etapas.', ], [ 'name' => 'Grand Jour', 'slug' => 'grand-jour', 'level' => '03 / FINAL', 'tag' => 'Assessoria final', - 'subtitle' => 'O planejamento está pronto. Agora é hora de viver.', - 'summary' => 'Para casais na reta final que precisam de uma equipe para assumir alinhamentos, cronograma e operação.', + 'subtitle' => 'Para quem já planejou e precisa de alguém para assumir a operação.', + 'summary' => 'Indicada para casais que estão na reta final dos preparativos e já possuem a maior parte do casamento definida.', 'scope_items' => [ 'Imersão no planejamento existente', - 'Conferência das informações', - 'Alinhamento dos fornecedores', + 'Conferência das informações e contratos dos fornecedores', + 'Alinhamento e comunicação com os profissionais envolvidos', 'Organização do cronograma final', - 'Gestão da operação do evento', + 'Orientação sobre os últimos detalhes', + 'Coordenação dos fornecedores no evento', + 'Acompanhamento da montagem e dos momentos do casamento', + 'Gestão da operação durante o grande dia', ], 'cta_label' => 'Quero conhecer a Grand Jour', 'compare_heading' => 'Entregar a operação para a Amare', - 'compare_summary' => 'O projeto está pronto e o foco passa a ser alinhamento e execução.', + 'compare_summary' => 'O projeto está pronto; o foco passa a ser alinhamento e execução.', 'sort_order' => 3, 'eyebrow' => 'Assessoria', 'title_line' => 'Assessoria', 'title_emphasis' => 'Final', - 'hero_lead' => 'Para assumir os alinhamentos e a operação quando o grande dia está próximo.', + 'hero_lead' => 'A Amare assume a condução operacional, mergulha no planejamento construído pelo casal e transforma as informações em uma execução organizada e alinhada.', 'benefits' => [ - ['icon_key' => 'checklist', 'label' => 'Imersão no que já existe'], - ['icon_key' => 'users', 'label' => 'Alinhamento de fornecedores'], + ['icon_key' => 'checklist', 'label' => 'Imersão no planejamento'], + ['icon_key' => 'users', 'label' => 'Fornecedores alinhados'], ['icon_key' => 'calendar', 'label' => 'Cronograma final'], - ['icon_key' => 'heart', 'label' => 'Operação com leveza'], + ['icon_key' => 'heart', 'label' => 'Operação no grande dia'], ], 'included_items' => [ - ['icon_key' => 'checklist', 'title' => 'Imersão no planejamento', 'description' => 'Entendemos cada decisão já tomada.'], - ['icon_key' => 'map', 'title' => 'Alinhamento de fornecedores', 'description' => 'Contatos e prazos sob cuidado.'], - ['icon_key' => 'calendar', 'title' => 'Cronograma final', 'description' => 'Cada etapa posicionada na reta final.'], - ['icon_key' => 'spark', 'title' => 'Ensaios e detalhes', 'description' => 'Produção e logística nos detalhes.'], - ['icon_key' => 'users', 'title' => 'Operação do evento', 'description' => 'Gestão da equipe e do dia a dia.'], - ['icon_key' => 'heart', 'title' => 'Dia do evento', 'description' => 'Coordenação total para o casal viver o momento.'], + ['icon_key' => 'checklist', 'title' => 'Imersão no planejamento', 'description' => 'A Amare mergulha no que o casal já decidiu.'], + ['icon_key' => 'map', 'title' => 'Contratos e informações', 'description' => 'Conferência do combinado com cada profissional.'], + ['icon_key' => 'users', 'title' => 'Alinhamento dos envolvidos', 'description' => 'Comunicação centralizada na reta final.'], + ['icon_key' => 'calendar', 'title' => 'Cronograma final', 'description' => 'A operação do grande dia ganha ordem.'], + ['icon_key' => 'spark', 'title' => 'Últimos detalhes', 'description' => 'Orientação para fechar o que ainda falta.'], + ['icon_key' => 'heart', 'title' => 'Gestão da operação', 'description' => 'Montagem, momentos e condução no dia do casamento.'], ], - 'audience_heading' => 'Para quem é este pacote', - 'audience_intro' => 'Para casais já planejados que querem chegar ao grande dia com equipe e operação no lugar.', + 'audience_heading' => 'Para quem é esta modalidade', + 'audience_intro' => 'Porque, na reta final, vocês não precisam de mais tarefas. Precisam de alguém que assuma a condução.', 'audience_points' => [ - 'Casamentos já planejados', - 'Casais na reta final', - 'Quem precisa de operação no dia', - 'Quem quer viver o momento com leveza', + 'Casais na reta final dos preparativos', + 'Quem já definiu a maior parte do casamento', + 'Quem quer entregar a operação do grande dia', ], - 'final_cta_heading' => 'Pronta para o grande dia?', - 'final_cta_body' => 'Conte a data do seu evento e receba uma proposta.', + 'final_cta_heading' => 'Vamos assumir a operação?', + 'final_cta_body' => 'Conte a data e o que já está definido. A Amare entra para conduzir o grande dia.', ], ]; diff --git a/tests/Feature/Marketing/WeddingPackageTest.php b/tests/Feature/Marketing/WeddingPackageTest.php index 43b23a5..4ce248b 100644 --- a/tests/Feature/Marketing/WeddingPackageTest.php +++ b/tests/Feature/Marketing/WeddingPackageTest.php @@ -38,6 +38,33 @@ class WeddingPackageTest extends TestCase ['Essenza', 'Conduzione', 'Grand Jour'], WeddingPackage::query()->published()->orderBy('sort_order')->pluck('name')->all(), ); + + $essenza = WeddingPackage::query()->where('name', 'Essenza')->first(); + $this->assertNotNull($essenza); + $this->assertSame('Assessoria completa', $essenza->tag); + $this->assertSame('Do primeiro planejamento ao grande dia.', $essenza->subtitle); + $this->assertStringContainsString('desde o início da organização', (string) $essenza->summary); + $this->assertContains('Estruturação e acompanhamento do planejamento', $essenza->scope_items); + $this->assertSame( + ['Casais no início da organização', 'Quem ainda está estruturando etapas importantes', 'Quem quer acompanhamento do planejamento à execução'], + $essenza->audience_points, + ); + + $publicCopy = WeddingPackage::query()->published()->get()->map(fn (WeddingPackage $package): string => json_encode([ + $package->summary, + $package->subtitle, + $package->hero_lead, + $package->scope_items, + $package->included_items, + $package->audience_intro, + $package->final_cta_body, + ], JSON_THROW_ON_ERROR))->implode(' '); + + $this->assertStringNotContainsString('R$', $publicCopy); + $this->assertStringNotContainsString('3.500', $publicCopy); + $this->assertStringNotContainsString('Assessoria VIP', $publicCopy); + $this->assertStringNotContainsString('90 km', $publicCopy); + $this->assertStringNotContainsString('3,49%', $publicCopy); } public function test_factory_generates_a_slug_and_autofills_blank_slug_from_name(): void -- 2.49.1 From 9ee9b51b0c27968aa4ea979ba82a665011cacdeb Mon Sep 17 00:00:00 2001 From: manoel freitas Date: Thu, 13 Aug 2026 23:39:29 -0300 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20CTA=20de=20orienta=C3=A7=C3=A3o=20d?= =?UTF-8?q?as=20modalidades=20via=20WhatsApp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A banda "ainda não sabe" abre wa.me com mensagem de orientação; sem número, cai no briefing. Co-authored-by: Cursor --- app/Support/PackageContactLink.php | 28 +++++++++++++++++-- .../views/components/home/packages.blade.php | 13 ++++++--- .../views/pages/services/index.blade.php | 1 - .../PublicSite/HomePageContentTest.php | 8 +++++- .../PublicSite/ServicesPageCtaTest.php | 8 +++++- 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/app/Support/PackageContactLink.php b/app/Support/PackageContactLink.php index 563b49b..37a2b6a 100644 --- a/app/Support/PackageContactLink.php +++ b/app/Support/PackageContactLink.php @@ -8,20 +8,44 @@ use App\Models\SiteSetting; final class PackageContactLink { + public const GUIDANCE_MESSAGE = 'Olá, ainda não sei qual modalidade de assessoria faz sentido para o meu casamento e gostaria de orientação.'; + /** * Resolve the contextual contact link for a wedding package modality. * * @return array{href: string, isWhatsapp: bool} */ public static function for(SiteSetting $settings, string $packageName): array + { + return self::resolve( + $settings, + 'Olá, gostaria de conversar sobre a modalidade '.$packageName.' para meu casamento.', + route('briefing', ['servico_interesse' => $packageName]), + ); + } + + /** + * WhatsApp (or briefing fallback) when the visitor does not know which modality to choose. + * + * @return array{href: string, isWhatsapp: bool} + */ + public static function forGuidance(SiteSetting $settings): array + { + return self::resolve($settings, self::GUIDANCE_MESSAGE, route('briefing')); + } + + /** + * @return array{href: string, isWhatsapp: bool} + */ + private static function resolve(SiteSetting $settings, string $whatsappMessage, string $fallbackHref): array { $digits = preg_replace('/\D/', '', (string) $settings->whatsapp_number); $isWhatsapp = strlen($digits) >= 10; return [ 'href' => $isWhatsapp - ? 'https://wa.me/'.$digits.'?text='.rawurlencode('Olá, gostaria de conversar sobre a modalidade '.$packageName.' para meu casamento.') - : route('briefing', ['servico_interesse' => $packageName]), + ? 'https://wa.me/'.$digits.'?text='.rawurlencode($whatsappMessage) + : $fallbackHref, 'isWhatsapp' => $isWhatsapp, ]; } diff --git a/resources/views/components/home/packages.blade.php b/resources/views/components/home/packages.blade.php index 18288c2..62f3594 100644 --- a/resources/views/components/home/packages.blade.php +++ b/resources/views/components/home/packages.blade.php @@ -14,9 +14,6 @@ 'note' => 'Nomenclaturas exibidas conforme materiais/reunião; confirmar versão final antes da publicação.', ]) -@php - $bandHref = $bandCtaHref ?? route('briefing'); -@endphp
@endif + @php($guidanceLink = \App\Support\PackageContactLink::forGuidance($settings)) + @php($bandHref = filled($bandCtaHref) ? $bandCtaHref : $guidanceLink['href']) + @php($bandIsWhatsapp = ! filled($bandCtaHref) && $guidanceLink['isWhatsapp'])

Ainda não sabe qual modalidade é ideal?

{{ $bandBody }}

- + Conversar com a Amare
diff --git a/resources/views/pages/services/index.blade.php b/resources/views/pages/services/index.blade.php index 5237ac7..1aad19d 100644 --- a/resources/views/pages/services/index.blade.php +++ b/resources/views/pages/services/index.blade.php @@ -47,7 +47,6 @@ :show-intro="false" kicker="tag" :show-subtitle="true" - :band-cta-href="route('briefing')" band-body="Conte um pouco sobre o casamento. A Amare entende o momento de vocês e orienta o melhor formato de acompanhamento sem depender de um quiz automático." :show-note="false" /> diff --git a/tests/Feature/PublicSite/HomePageContentTest.php b/tests/Feature/PublicSite/HomePageContentTest.php index f581f88..a1298f8 100644 --- a/tests/Feature/PublicSite/HomePageContentTest.php +++ b/tests/Feature/PublicSite/HomePageContentTest.php @@ -8,6 +8,7 @@ use App\Models\PortfolioCase; use App\Models\SiteSetting; use App\Models\Testimonial; use App\Models\WeddingPackage; +use App\Support\PackageContactLink; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; @@ -213,7 +214,12 @@ class HomePageContentTest extends TestCase false, ) ->assertSee('target="_blank"', false) - ->assertDontSee(route('briefing', ['servico_interesse' => 'Grand Jour']), false); + ->assertDontSee(route('briefing', ['servico_interesse' => 'Grand Jour']), false) + ->assertSee('data-testid="package-guidance-cta"', false) + ->assertSee( + 'https://wa.me/5511988887777?text='.rawurlencode(PackageContactLink::GUIDANCE_MESSAGE), + false, + ); } public function test_corporate_steps_and_placeholder_render_from_settings(): void diff --git a/tests/Feature/PublicSite/ServicesPageCtaTest.php b/tests/Feature/PublicSite/ServicesPageCtaTest.php index e2f36c1..3b5dc31 100644 --- a/tests/Feature/PublicSite/ServicesPageCtaTest.php +++ b/tests/Feature/PublicSite/ServicesPageCtaTest.php @@ -6,6 +6,7 @@ namespace Tests\Feature\PublicSite; use App\Models\SiteSetting; use App\Models\WeddingPackage; +use App\Support\PackageContactLink; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; @@ -31,7 +32,12 @@ class ServicesPageCtaTest extends TestCase false, ) ->assertSee('target="_blank"', false) - ->assertDontSee(route('briefing', ['servico_interesse' => 'Grand Jour']), false); + ->assertDontSee(route('briefing', ['servico_interesse' => 'Grand Jour']), false) + ->assertSee('data-testid="package-guidance-cta"', false) + ->assertSee( + 'https://wa.me/5511988887777?text='.rawurlencode(PackageContactLink::GUIDANCE_MESSAGE), + false, + ); } public function test_package_cta_falls_back_to_briefing_without_whatsapp_number(): void -- 2.49.1