Add staff-presented SMS consent flow on customer record

- New GET/POST Customers/SmsConsent/{id}: full-screen kiosk-layout page staff
  opens and hands to the customer to read TCPA consent language and tap I Agree
- On agreement: sets Customer.NotifyBySms, SmsConsentedAt (UTC), SmsConsentMethod
  = "InPerson", clears SmsOptedOutAt
- Redirects back if customer has already consented (no double-consent)
- Customer Details: "Get SMS Consent" badge link shown when NotifyBySms is false;
  SMS on badge shows consent date on hover when consented

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-13 22:50:49 -04:00
parent 66231822af
commit b69ff6db3a
3 changed files with 120 additions and 1 deletions
@@ -175,7 +175,8 @@
}
@if (Model.NotifyBySms)
{
<span class="badge bg-success bg-opacity-10 text-success border border-success border-opacity-25">
<span class="badge bg-success bg-opacity-10 text-success border border-success border-opacity-25"
title="@(Model.SmsConsentedAt.HasValue ? "Consented " + Model.SmsConsentedAt.Value.ToLocalTime().ToString("MM/dd/yyyy") : "")">
<i class="bi bi-chat-fill me-1"></i>SMS on
</span>
}
@@ -184,6 +185,11 @@
<span class="badge bg-secondary bg-opacity-10 text-secondary border border-secondary border-opacity-25">
<i class="bi bi-chat-slash me-1"></i>SMS off
</span>
<a href="/Customers/SmsConsent/@Model.Id"
class="badge bg-primary bg-opacity-10 text-primary border border-primary border-opacity-25 text-decoration-none"
title="Present SMS consent form to customer">
<i class="bi bi-chat-dots me-1"></i>Get SMS Consent
</a>
}
</div>
</div>
@@ -0,0 +1,45 @@
@model int
@{
Layout = "~/Views/Shared/_KioskLayout.cshtml";
ViewData["Title"] = "SMS Consent";
string customerName = ViewBag.CustomerName as string ?? "Customer";
}
<div class="kiosk-card">
<h2 class="fw-bold mb-1" style="font-size:1.6rem;">SMS Notifications</h2>
<p class="text-muted mb-4">Please read the following and tap <strong>I Agree</strong> to opt in.</p>
<form method="post" action="/Customers/SmsConsent/@Model">
@Html.AntiForgeryToken()
<input type="hidden" name="agreed" value="true" />
<div class="kiosk-terms-scroll mb-4">
<strong>SMS Consent &amp; Opt-In</strong>
<p class="mt-2">
By tapping <em>I Agree</em> below, <strong>@customerName</strong> consents to receive
SMS text messages from @(ViewBag.CompanyName ?? "this shop") regarding order status
updates, pickup notifications, and other information related to your powder coating
services.
</p>
<p>
Message frequency varies. Message and data rates may apply.
You may opt out at any time by replying <strong>STOP</strong> to any message.
Reply <strong>HELP</strong> for assistance.
</p>
<p class="mb-0">
Your mobile number will not be shared with third parties or used for marketing
unrelated to your orders.
</p>
</div>
<div class="d-flex gap-3">
<a href="/Customers/Details/@Model" class="btn btn-outline-secondary"
style="min-height:64px;border-radius:12px;font-size:1.1rem;flex:0 0 auto;padding:0 2rem;">
<i class="bi bi-x-lg me-1"></i> No Thanks
</a>
<button type="submit" class="btn btn-success kiosk-btn">
<i class="bi bi-check-circle me-2"></i> I Agree
</button>
</div>
</form>
</div>