Sweep all .cshtml files for encoding corruption; add pre-commit guard

Replace all corruption variants with HTML entities across 226 view files:
- 3-char UTF-8-as-Win1252 sequences (ae-corruption)
- Standalone smart/curly quotes that break C# Razor expressions
- Partially re-corrupted variants where the 3rd byte was normalised to ASCII

tools/Fix-Encoding.ps1: re-runnable sweep; uses [char] code points so the
script itself never contains a literal non-ASCII character; supports -DryRun

.githooks/pre-commit: blocks commits containing the ae-corruption byte
signature (xc3xa2xe2x82xac); git core.hooksPath = .githooks so the
hook is repo-committed and active for all future work on this machine.

Build clean; 225 unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 21:37:10 -04:00
parent 21b39161a3
commit a0bdd2b5b4
252 changed files with 1785 additions and 1633 deletions
@@ -21,7 +21,7 @@
</h2>
<p>
The Customer Intake Kiosk lets walk-in customers fill out their own intake form on a front-desk tablet
no staff assistance required. When they're done, a <strong>customer record</strong> is automatically
&mdash; no staff assistance required. When they're done, a <strong>customer record</strong> is automatically
created (or matched to an existing one), a <strong>Draft Quote or Pending Job</strong> is created
depending on your setting, and your team receives an in-app notification.
</p>
@@ -45,7 +45,7 @@
</li>
<li class="mb-2">
On the tablet, open a browser and navigate to <code>/Kiosk/Welcome</code>. You'll see your
company logo and a "Ready" indicator the tablet is now in kiosk mode.
company logo and a "Ready" indicator &mdash; the tablet is now in kiosk mode.
</li>
<li class="mb-2">
<strong>Add to Home Screen</strong> on iOS/Android for a full-screen, app-like experience that
@@ -67,7 +67,7 @@
<h3 class="h6 fw-semibold mt-3 mb-2">In-Person (tablet at front desk)</h3>
<ol>
<li class="mb-1">The tablet sits on the Welcome screen the customer sees your logo and a "Ready" status dot.</li>
<li class="mb-1">The tablet sits on the Welcome screen &mdash; the customer sees your logo and a "Ready" status dot.</li>
<li class="mb-1">A staff member clicks <strong>Start Intake</strong> on the Dashboard (in the Kiosk card).</li>
<li class="mb-1">The tablet detects the new session within 3 seconds and automatically navigates to the intake form.</li>
<li class="mb-1">The customer fills out <strong>3 steps</strong>: Contact info → Job description → Terms &amp; signature.</li>
@@ -85,7 +85,7 @@
<li class="mb-1">Or use the <strong>Send Intake Link</strong> button on the Dashboard Kiosk card.</li>
<li class="mb-1">Enter the customer's email address and send.</li>
<li class="mb-1">The customer receives an email with a secure link and completes the same 3-step form on their own device.</li>
<li class="mb-1">Remote sessions don't require a drawn signature a checkbox agreement is used instead.</li>
<li class="mb-1">Remote sessions don't require a drawn signature &mdash; a checkbox agreement is used instead.</li>
</ol>
</section>
@@ -99,12 +99,12 @@
</p>
<ul>
<li>
<strong>Create a Quote</strong> (default) a Draft quote is created for staff to review and price
<strong>Create a Quote</strong> (default) &mdash; a Draft quote is created for staff to review and price
before work begins. The terms shown to the customer will say "subject to a formal quote." Use this
if you price after seeing the parts.
</li>
<li>
<strong>Create a Job</strong> a Pending job is created immediately. The terms will say "a team
<strong>Create a Job</strong> &mdash; a Pending job is created immediately. The terms will say "a team
member will reach out about pricing." Use this if you price on the spot and want the work order
ready right away.
</li>
@@ -117,16 +117,16 @@
</h2>
<p>When a customer submits their intake form, the system automatically:</p>
<ul>
<li><strong>Matches or creates a Customer</strong> searches by email first, then phone. If no match, a new non-commercial customer record is created.</li>
<li><strong>Matches or creates a Customer</strong> &mdash; searches by email first, then phone. If no match, a new non-commercial customer record is created.</li>
<li>
<strong>Creates a Draft Quote or Pending Job</strong> depending on your
<strong>Creates a Draft Quote or Pending Job</strong> &mdash; depending on your
<a href="/CompanySettings?tab=kiosk">Kiosk Output Setting</a>. Quote mode creates a Draft quote
(Normal priority); Job mode creates a Pending job with the customer's description and intake source
in Special Instructions.
</li>
<li><strong>Applies SMS consent</strong> if the customer opted in, their customer record is updated with <code>NotifyBySms = true</code> and the consent timestamp (TCPA-compliant).</li>
<li><strong>Applies SMS consent</strong> &mdash; if the customer opted in, their customer record is updated with <code>NotifyBySms = true</code> and the consent timestamp (TCPA-compliant).</li>
<li>
<strong>Fires an in-app notification</strong> your team's notification bell shows
<strong>Fires an in-app notification</strong> &mdash; your team's notification bell shows
"Walk-in Intake Submitted" (or "Remote Intake Submitted" for remote sessions) with a link to
the Intakes page.
</li>
@@ -147,9 +147,9 @@
<li>Job description snippet</li>
<li>Session type (In-Person or Remote) and status badge</li>
<li>SMS opt-in indicator</li>
<li><strong>View Quote</strong> button appears when the kiosk is set to Quote mode; opens the auto-created draft quote</li>
<li><strong>View Job</strong> button appears when the kiosk is set to Job mode; opens the auto-created job</li>
<li><strong>Customer</strong> button opens the matched or created customer record</li>
<li><strong>View Quote</strong> button &mdash; appears when the kiosk is set to Quote mode; opens the auto-created draft quote</li>
<li><strong>View Job</strong> button &mdash; appears when the kiosk is set to Job mode; opens the auto-created job</li>
<li><strong>Customer</strong> button &mdash; opens the matched or created customer record</li>
</ul>
<div class="alert alert-info alert-permanent">
<i class="bi bi-info-circle me-2"></i>
@@ -164,23 +164,23 @@
<i class="bi bi-exclamation-triangle text-primary me-2"></i>Troubleshooting
</h2>
<dl>
<dt>Kiosk Welcome screen shows "Connection issue retrying"</dt>
<dd class="mb-3">The tablet can't reach the server. Check the tablet's Wi-Fi connection. Once connectivity is restored the status dot automatically turns green no refresh needed.</dd>
<dt>Kiosk Welcome screen shows "Connection issue &mdash; retrying&hellip;"</dt>
<dd class="mb-3">The tablet can't reach the server. Check the tablet's Wi-Fi connection. Once connectivity is restored the status dot automatically turns green &mdash; no refresh needed.</dd>
<dt>Kiosk doesn't respond when staff clicks Start Intake</dt>
<dd class="mb-3">The tablet polls every 3 seconds. Wait up to 3 seconds after clicking Start Intake. If it still doesn't respond, reload the Welcome page on the tablet. Make sure the tablet is on the same domain as the server (use HTTPS).</dd>
<dt>The tablet shows the wrong company logo or no logo</dt>
<dd class="mb-3">Upload your company logo at Settings → Company Settings → Logo. The kiosk reads your logo directly no separate kiosk logo setting is needed.</dd>
<dd class="mb-3">Upload your company logo at Settings → Company Settings → Logo. The kiosk reads your logo directly &mdash; no separate kiosk logo setting is needed.</dd>
<dt>Signature pad doesn't work on the tablet</dt>
<dd class="mb-3">Use a capacitive stylus or fingertip the signature pad requires touch input. Make sure the browser isn't in desktop mode (check "Request Desktop Site" is off). The signature is only required for In-Person sessions.</dd>
<dd class="mb-3">Use a capacitive stylus or fingertip &mdash; the signature pad requires touch input. Make sure the browser isn't in desktop mode (check "Request Desktop Site" is off). The signature is only required for In-Person sessions.</dd>
<dt>Submission fails no job or customer created</dt>
<dt>Submission fails &mdash; no job or customer created</dt>
<dd class="mb-3">This usually means Seed Data hasn't been run for your company. Ask your administrator to go to Platform Management → Seed Data and run the seed. This creates the required job status and priority lookup rows.</dd>
<dt>AI quote on the quote wizard times out on mobile</dt>
<dd class="mb-3">Photos are automatically compressed before upload. If it still times out, your connection may be slow the spinner will say "Still analyzing" if it's taking longer than 30 seconds. Try again on a stronger connection.</dd>
<dd class="mb-3">Photos are automatically compressed before upload. If it still times out, your connection may be slow &mdash; the spinner will say "Still analyzing&hellip;" if it's taking longer than 30 seconds. Try again on a stronger connection.</dd>
</dl>
</section>