3.0 KiB
3.0 KiB
Task 03 — Request Demo page with MailPit form
- Status: Done — 2026-08-20
- Depends on: 01
- Size: M
Goal
Create the Request Demo page at /RequestDemo with a form that emails its submission to MailPit (tools.host.domain:1025, recipient [email protected]) via the existing MailSender. Same send/success/error pattern as the Contact page (Task 02).
Files
- Create:
plushealthtech/Pages/RequestDemo.cshtml - Create:
plushealthtech/Pages/RequestDemo.cshtml.cs
Steps
-
PageModel (
RequestDemoModel : PageModel)- Inject
MailSender(+ logger). [BindProperty]fields with DataAnnotations:Name—[Required],[StringLength(200)]Email—[Required],[EmailAddress],[StringLength(320)]Organization—[Required],[StringLength(200)]PracticeType— select: Healthcare system, Hospital, Clinic, Veterinary practice, Other (optional)ProductsOfInterest— select: Clinical Decision Support, Patient Management, Veterinary Solutions, Multiple / not sure (optional)Message—[StringLength(5000)](optional)
Success/Errorflags,OnGetreset.OnPost()same contract as Task 02: validate → build plain-textField: valuebody →SendAsync($"New demo request — {Organization}", body)→ success flag; SMTP failure → generic error banner + log.
- Inject
-
View (
RequestDemo.cshtml)@page,@model RequestDemoModel,ViewData["Title"] = "Request Demo".- Marketing-flavored hero (one-line value prop, 2–3 trust bullets like "FHIR®-ready" / "24/7 clinical support" — reuse Index hero metrics) + the form card, Tailwind styling consistent with the site.
@Html.AntiforgeryToken(), per-field validation spans, success/error rendering identical in behavior to Contact.- Close with a secondary CTA: "Prefer to talk? Visit the Contact page." →
/Contact.
Acceptance criteria
GET /RequestDemorenders; build green.- Required fields enforced; selects render all options.
- Valid submit → success panel shown; MailPit shows the message from
[email protected]to[email protected]with subjectNew demo request — {Organization}(e2e verified 2026-08-20, ahead of Task 13). - With MailPit down → friendly error banner, exception in app log, no stack trace in the browser.
Notes
- Antiforgery: the form uses
asp-page="/RequestDemo", which auto-injects__RequestVerificationToken— the explicit@Html.AntiforgeryToken()from the spec is unnecessary and would duplicate the field (same approach as the Contact page). - SMTP-down path verified by running the app with
Smtp__Host=127.0.0.1 Smtp__Port=1(env override, no config change): banner rendered,SmtpException (SocketException 10061)logged with sender context, response body clean. - Validation confirmed over HTTP: empty POST → "required" messages on Name/Email/Organization only; bad email → "not a valid e-mail address"; both selects render their full option lists with a placeholder.