{# SyncKit billing panel — included per-app from user_synckit.html and project_synckit.html. Parent context must expose `app: SyncAppRow` with `app.billing: Option`. Two pricing modes (driven by the `enforcement_mode` radio): bulk — developer sets storage_gb_cap. Price = storage_gb_cap × rate. per_key — developer sets key_cap + gb_per_key. Price = key_cap × gb_per_key × rate. Pricing-formula constants live on data-* attrs on the .synckit-billing root so static/synckit-billing.js can mirror monthly_price_cents() without duplicating values. They must stay in sync with src/synckit_billing.rs. #} {% if let Some(b) = app.billing %}
{% if b.is_internal %}Internal{% else if b.status == "draft" %}Draft{% else if b.status == "active" %}Active{% else if b.status == "suspended_unpaid" %}Past due{% else if b.status == "canceled" %}Canceled{% else %}{{ b.status }}{% endif %} {% if !b.price_display.is_empty() %} {{ b.price_display }} {% endif %} Billing
{% if b.is_internal %}

First-party app — billing is not collected.

{% else %} {# Setup step: no Stripe customer yet → show "Set up billing" button. #} {% if !b.has_customer %}

Set up a payment method to enable Cloud Sync billing for this app.

{% endif %} {# Knob picker: shown for has_customer + draft/active. Canceled apps see a Reactivate hint. #} {% if b.has_customer && b.status != "canceled" %}
GB total
max active keys
storage allotment per key
$0.31 / month — $0.03/GB, floored at $0.31 (Stripe fee)
{% if b.status == "draft" %} {% else %} {% endif %}
{% endif %} {# Usage gauges (storage enforced; egress and keys shown as stats). #} {% if b.status == "active" || b.status == "suspended_unpaid" %}

Usage this period

Storage {{ b.storage_display }}
Egress {{ b.egress_display }}
{% if b.enforcement_mode == "per_key" %}
Keys {{ b.keys_claimed }}{% if let Some(c) = b.key_cap %} / {{ c }}{% endif %}
{% if !b.top_keys.is_empty() %}
Storage by key top {{ b.top_keys.len() }} by usage
{% for k in b.top_keys %}
{{ k.key }} {{ k.display }}
{% endfor %} {% if b.more_keys %}

More keys not shown. Fetch the full list via POST /api/sync/keys/list.

{% endif %}
{% endif %} {% endif %} {% if !b.period_end_display.is_empty() %}

{{ b.period_end_display }}

{% endif %}
{% endif %} {# Manage / cancel actions: shown for active and past-due. #} {% if b.status == "active" || b.status == "suspended_unpaid" %}
{% endif %} {% if b.status == "canceled" %}

Billing for this app is canceled. Recreate the app or contact support to reactivate.

{% endif %} {% endif %}
{% endif %}