{{- /* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial */ -}} {{- /* SPDX-FileCopyrightText: 2025-2026 Christian Galo */ -}} {{/* operator_product_readiness.html Purchasability readiness section. Its own partial so it can poll for live updates while a Stripe sync is in flight: while SyncPending, the wrapper carries hx-get/hx-trigger="every 3s" against the readiness partial route, which replies 286 (htmx's stop-polling status) plus a poll-attr-free section once the state is terminal, so the swap removes the poller even without the 286. Declarative hx-* only; CSP-safe. Built from the page-anatomy parts: sectionHeader outside the card; check states (met, missing, sync pending, sync failed) render through statusBadge; annotations (Purchasable, Incomplete, Shown, Not shown, Not applicable, Unlisted, No rules) render as text per design D3. */}}
{{ template "sectionHeader" .ReadinessHeader }}
{{/* The verdict is the panel's one significant statement, so it renders as an alert strip, not a row-sized badge (maintainer, 2026-08-31). product-management "The readiness panel prints its verdict": the template always prints .Readiness.Verdict, the string the evaluation computes ("Purchasable", "Purchasable; not shown in the member catalog", "Ready to grant" for an unlisted product, "Inactive", "Incomplete; missing: ..."), and never a literal (such as "Purchasable.") derived from the Purchasable boolean in its place. */}} {{ if .Readiness.Purchasable }}
{{ .Readiness.Verdict }}
{{ else }}
{{ .Readiness.Verdict }}
{{ end }}
    {{ range .Readiness.Rows }}
  • {{ .Label }} {{ if eq .State "n/a" }} Not applicable {{ else if eq .State "unlisted" }} Unlisted; issued as grants {{ else if eq .State "no_rules" }} No rules {{ else if eq .State "shown" }} Shown {{ else if eq .State "hidden" }} Not shown {{ else }} {{ template "statusBadge" .StateBadge }} {{ end }}
    {{ if and (or .DetailAlways (ne .State "met")) .Detail }} {{ .Detail }}{{ if .Href }} Settings{{ end }} {{ end }}
  • {{ end }}
{{ if .Readiness.CanSyncStripe }}
{{ else if .Readiness.CanRetryStripe }} {{/* form-conventions "Button weight follows the button's role" (design D19): a retry is a positive non-commit, not a destructive commit, so it renders outline-primary like Sync to Stripe above, never btn-danger (reserved for a destructive commit inside the confirm modal). */}}
The last sync to Stripe failed; retry to run it again.
{{ else if not .Readiness.StripeConfigured }} {{ end }}