e476b4744d
Subscription expiry (SubscriptionExpiryBackgroundService): - Trials with no grace period now go directly Active -> Expired instead of briefly entering GracePeriod for a day, which was causing repeated 'Grace Period Started' admin notification emails - Remove redundant isTrial variable (query already filters to non-Stripe companies, so all processed companies are trials by definition) - Save per-company inside the loop so a single SaveChangesAsync failure no longer discards all other companies' status changes and notification log entries (which was the other cause of repeated emails) HTML entities in page titles (33 views): - Replace – / — with plain ' - ' in ViewData["Title"] C# strings; Razor HTML-encodes these when rendering @ViewData["Title"], causing browsers to display the literal text '–' instead of a dash Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
92 lines
3.8 KiB
Plaintext
92 lines
3.8 KiB
Plaintext
@using PowderCoating.Core.Entities
|
|
@model StripeWebhookEvent
|
|
@{
|
|
ViewData["Title"] = $"Webhook Event - {Model.EventId}";
|
|
var statusClass = Model.Status switch
|
|
{
|
|
StripeWebhookEventStatus.Processed => "success",
|
|
StripeWebhookEventStatus.Failed => "danger",
|
|
StripeWebhookEventStatus.Ignored => "secondary",
|
|
_ => "warning"
|
|
};
|
|
}
|
|
|
|
<div class="container-fluid py-3" style="max-width:960px">
|
|
<div class="d-flex align-items-center gap-3 mb-3">
|
|
<a asp-action="Index" class="btn btn-outline-secondary">
|
|
<i class="bi bi-arrow-left me-1"></i>Back
|
|
</a>
|
|
<h4 class="mb-0">
|
|
<i class="bi bi-stripe me-2 text-primary"></i>Webhook Event
|
|
</h4>
|
|
<span class="badge bg-@statusClass fs-6">@Model.Status</span>
|
|
</div>
|
|
|
|
<div class="row g-3 mb-3">
|
|
<div class="col-md-6">
|
|
<div class="card shadow-sm h-100">
|
|
<div class="card-header fw-semibold py-2">Event Details</div>
|
|
<div class="card-body">
|
|
<dl class="row mb-0 small">
|
|
<dt class="col-5 text-muted">Event ID</dt>
|
|
<dd class="col-7 font-monospace">@Model.EventId</dd>
|
|
|
|
<dt class="col-5 text-muted">Type</dt>
|
|
<dd class="col-7"><span class="badge bg-light text-dark border">@Model.EventType</span></dd>
|
|
|
|
<dt class="col-5 text-muted">Company ID</dt>
|
|
<dd class="col-7">@Html.Raw(Model.CompanyId.HasValue ? Model.CompanyId.ToString() : "—")</dd>
|
|
|
|
<dt class="col-5 text-muted">Status</dt>
|
|
<dd class="col-7"><span class="badge bg-@statusClass">@Model.Status</span></dd>
|
|
|
|
<dt class="col-5 text-muted">Received At</dt>
|
|
<dd class="col-7">@Model.ReceivedAt.ToString("MM/dd/yyyy HH:mm:ss") UTC</dd>
|
|
|
|
<dt class="col-5 text-muted">Processed At</dt>
|
|
<dd class="col-7">@Html.Raw(Model.ProcessedAt.HasValue ? Model.ProcessedAt.Value.ToString("MM/dd/yyyy HH:mm:ss") + " UTC" : "—")</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@if (!string.IsNullOrEmpty(Model.ErrorMessage))
|
|
{
|
|
<div class="col-md-6">
|
|
<div class="card shadow-sm h-100 border-danger">
|
|
<div class="card-header fw-semibold py-2 text-danger">
|
|
<i class="bi bi-exclamation-triangle me-1"></i>Error
|
|
</div>
|
|
<div class="card-body">
|
|
<pre class="small mb-0 text-danger">@Model.ErrorMessage</pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="card shadow-sm">
|
|
<div class="card-header d-flex justify-content-between align-items-center py-2">
|
|
<span class="fw-semibold">Raw Payload</span>
|
|
<button class="btn btn-outline-secondary" onclick="copyJson()">
|
|
<i class="bi bi-clipboard me-1"></i>Copy
|
|
</button>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<pre id="json-payload" class="mb-0 p-3 small" style="background:#1e1e1e;color:#d4d4d4;max-height:600px;overflow-y:auto;border-radius:0 0 .375rem .375rem">@ViewBag.FormattedJson</pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@section Scripts {
|
|
<script>
|
|
function copyJson() {
|
|
const text = document.getElementById('json-payload').textContent;
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
const btn = event.currentTarget;
|
|
btn.innerHTML = '<i class="bi bi-check me-1"></i>Copied';
|
|
setTimeout(() => btn.innerHTML = '<i class="bi bi-clipboard me-1"></i>Copy', 2000);
|
|
});
|
|
}
|
|
</script>
|
|
}
|