Render hosted trial terminal conflicts as outcome pages

Move pre-checkout hosted trial conflicts onto the owned terminal outcome UX so users do not land back in an editable form for non-retryable duplicate-trial states.
This commit is contained in:
rcourtman
2026-03-25 11:27:10 +00:00
parent f15754f99a
commit 6ebb3fe226
3 changed files with 35 additions and 14 deletions
@@ -266,7 +266,8 @@ instance, not as a generic purchase funnel. Recovery-contact fields such as
work email and optional company name must remain clearly secondary to the
instance-bound entitlement handoff. Hosted form-stage issuance conflicts must
also preserve the canonical reason shape: duplicate recovery-email usage must
not be flattened into an organization-level message.
not be flattened into an organization-level message, and terminal conflicts
must render as owned hosted outcome UX rather than editable inline form state.
That same hosted owner also applies after Stripe returns to
`/trial-signup/complete`: customer-facing completion failures must stay inside
owned trial UX rather than dropping raw control-plane error strings, and they
+12 -4
View File
@@ -664,8 +664,12 @@ func (h *TrialSignupHandlers) HandleRequestVerification(w http.ResponseWriter, r
return
}
if conflict != nil {
data.ErrorMessage = trialSignupIssuanceConflictMessage(conflict)
h.renderTrialSignupPage(w, r, http.StatusConflict, data)
h.renderTrialSignupFailurePage(w, r, http.StatusConflict, trialSignupFailureDataForPage(
h.cfg,
data,
trialSignupFailureConflict,
trialSignupIssuanceConflictMessage(conflict),
))
return
}
}
@@ -842,8 +846,12 @@ func (h *TrialSignupHandlers) HandleCheckout(w http.ResponseWriter, r *http.Requ
return
}
if conflict != nil {
data.ErrorMessage = trialSignupIssuanceConflictMessage(conflict)
h.renderTrialSignupPage(w, r, http.StatusConflict, data)
h.renderTrialSignupFailurePage(w, r, http.StatusConflict, trialSignupFailureDataForPage(
h.cfg,
data,
trialSignupFailureConflict,
trialSignupIssuanceConflictMessage(conflict),
))
return
}
record = &TrialSignupRecord{
+21 -9
View File
@@ -186,9 +186,13 @@ func TestTrialSignupHandleRequestVerificationRejectsEmailThatAlreadyUsedTrial(t
if rec.Code != http.StatusConflict {
t.Fatalf("status=%d, want %d body=%q", rec.Code, http.StatusConflict, rec.Body.String())
}
if !strings.Contains(rec.Body.String(), "recovery email has already used a Pulse Pro trial") {
t.Fatalf("expected duplicate trial message, got %q", rec.Body.String())
}
assertTrialSignupFailurePageContains(t, rec.Body.String(),
"Trial already used",
"This recovery email has already used a Pulse Pro trial.",
"pulse.example.com",
"This trial request cannot be restarted for the same recovery contact or organization.",
)
assertTrialSignupFailurePageOmits(t, rec.Body.String(), "Continue To Secure Trial Setup", "<form")
}
func TestTrialSignupHandleRequestVerificationRejectsCorporateDomainReuse(t *testing.T) {
@@ -232,9 +236,13 @@ func TestTrialSignupHandleRequestVerificationRejectsCorporateDomainReuse(t *test
if secondRec.Code != http.StatusConflict {
t.Fatalf("status=%d, want %d body=%q", secondRec.Code, http.StatusConflict, secondRec.Body.String())
}
if !strings.Contains(secondRec.Body.String(), "organization has already used a Pulse Pro trial") {
t.Fatalf("expected organization duplicate trial message, got %q", secondRec.Body.String())
}
assertTrialSignupFailurePageContains(t, secondRec.Body.String(),
"Trial already used",
"This organization has already used a Pulse Pro trial.",
"pulse.example.com",
"This trial request cannot be restarted for the same recovery contact or organization.",
)
assertTrialSignupFailurePageOmits(t, secondRec.Body.String(), "Continue To Secure Trial Setup", "<form")
}
func TestTrialSignupHandleVerifyEmailConsumesSingleUseToken(t *testing.T) {
@@ -435,9 +443,13 @@ func TestTrialSignupHandleCheckoutRejectsEmailThatAlreadyUsedTrial(t *testing.T)
if rec.Code != http.StatusConflict {
t.Fatalf("status=%d, want %d body=%q", rec.Code, http.StatusConflict, rec.Body.String())
}
if !strings.Contains(rec.Body.String(), "recovery email has already used a Pulse Pro trial") {
t.Fatalf("expected duplicate email trial message, got %q", rec.Body.String())
}
assertTrialSignupFailurePageContains(t, rec.Body.String(),
"Trial already used",
"This recovery email has already used a Pulse Pro trial.",
"pulse.example.com",
"This trial request cannot be restarted for the same recovery contact or organization.",
)
assertTrialSignupFailurePageOmits(t, rec.Body.String(), "Continue To Secure Trial Setup", "<form")
}
func TestTrialSignupHandleCompleteRedirectsWithActivationToken(t *testing.T) {