Skip to content

Commit c0c2c6c

Browse files
simonhampclaude
andauthored
Fix HTML entities rendering in support form (#374)
The product card descriptions on the support request form were showing literal "&amp;" because passing interpolated attribute values to a Flux component re-escapes them. Replaced "&" with "and" to dodge the double-encoding entirely. Also replaced raw "&#10;" entities in the Steps to Reproduce placeholder with PHP_EOL via attribute binding so newlines render reliably, and swapped the "&#8984;" entity in the reply hint for the literal "⌘" character. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b7704a4 commit c0c2c6c

3 files changed

Lines changed: 43 additions & 6 deletions

File tree

resources/views/livewire/customer/support/create.blade.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@
3535

3636
<flux:radio.group wire:model.live="selectedProduct" variant="cards" class="flex-col">
3737
@foreach ([
38-
'mobile' => ['label' => 'Mobile', 'desc' => 'iOS & Android apps'],
39-
'desktop' => ['label' => 'Desktop', 'desc' => 'macOS, Windows & Linux apps'],
40-
'nativephp.com' => ['label' => 'nativephp.com', 'desc' => 'Website, account & billing'],
38+
'mobile' => ['label' => 'Mobile', 'desc' => 'iOS and Android apps'],
39+
'desktop' => ['label' => 'Desktop', 'desc' => 'macOS, Windows and Linux apps'],
40+
'nativephp.com' => ['label' => 'nativephp.com', 'desc' => 'Website, account and billing'],
4141
] as $value => $product)
42-
<flux:radio value="{{ $value }}" label="{{ $product['label'] }}" description="{{ $product['desc'] }}" />
42+
<flux:radio :value="$value" :label="$product['label']" :description="$product['desc']" />
4343
@endforeach
4444
</flux:radio.group>
4545
</div>
@@ -105,7 +105,7 @@
105105
wire:model="reproductionSteps"
106106
label="Steps to reproduce"
107107
rows="4"
108-
placeholder="1. Open the app&#10;2. Navigate to...&#10;3. Click on..."
108+
:placeholder="implode(PHP_EOL, ['1. Open the app', '2. Navigate to...', '3. Click on...'])"
109109
/>
110110

111111
<flux:field>

resources/views/livewire/customer/support/show.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
133133
</div>
134134

135135
<div class="mt-3 flex items-center justify-end gap-3">
136-
<flux:text class="text-xs">&#8984;/Ctrl + Enter to send</flux:text>
136+
<flux:text class="text-xs">/Ctrl + Enter to send</flux:text>
137137
<flux:button type="submit" variant="primary" icon="arrow-uturn-left">
138138
Send Reply
139139
</flux:button>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Tests\Feature;
4+
5+
use App\Livewire\Customer\Support\Create;
6+
use App\Models\License;
7+
use App\Models\User;
8+
use Illuminate\Foundation\Testing\RefreshDatabase;
9+
use Laravel\Cashier\Subscription;
10+
use Livewire\Livewire;
11+
use PHPUnit\Framework\Attributes\Test;
12+
use Tests\TestCase;
13+
14+
class SupportFormPlaceholderTest extends TestCase
15+
{
16+
use RefreshDatabase;
17+
18+
#[Test]
19+
public function reproduction_steps_placeholder_does_not_render_literal_html_entities(): void
20+
{
21+
config(['subscriptions.plans.max.stripe_price_id' => 'price_test_max_yearly']);
22+
$user = User::factory()->create();
23+
License::factory()->max()->active()->create(['user_id' => $user->id]);
24+
Subscription::factory()->for($user)->active()->create([
25+
'stripe_price' => 'price_test_max_yearly',
26+
]);
27+
28+
$html = Livewire::actingAs($user)
29+
->test(Create::class)
30+
->set('selectedProduct', 'mobile')
31+
->call('nextStep')
32+
->html();
33+
34+
$this->assertStringNotContainsString('&#10;', $html);
35+
$this->assertStringContainsString("1. Open the app\n2. Navigate to...\n3. Click on...", $html);
36+
}
37+
}

0 commit comments

Comments
 (0)