defmodule PlausibleWeb.Components.Billing.Notice do @moduledoc false use PlausibleWeb, :component require Plausible.Billing.Subscription.Status alias Plausible.Billing.{Subscription, Plans, Subscriptions} def active_grace_period(assigns) do if assigns.enterprise? do ~H""" """ else ~H""" """ end end def dashboard_locked(assigns) do ~H""" """ end attr(:current_team, :any, required: true) attr(:current_user, :atom, required: true) attr(:limit, :integer, required: true) attr(:resource, :string, required: true) attr(:rest, :global) def limit_exceeded(assigns) do ~H""" <.notice {@rest} title={"#{account_label(@current_team)} is limited to #{pretty_print_resource_limit(@limit, @resource)}"} data-test="limit-exceeded-notice" theme={:gray} show_icon={false} > To add more {@resource}, """ end defp pretty_print_resource_limit(1 = _limit, resource_plural) do "a single #{String.trim_trailing(resource_plural, "s")}" end defp pretty_print_resource_limit(limit, resource_plural) do "#{limit} #{resource_plural}" end attr(:subscription, :map, required: true) attr(:dismissable, :boolean, default: true) @doc """ Given a user with a cancelled subscription, this component renders a cancelled subscription notice. If the given user does not have a subscription or it has a different status, this function returns an empty template. It also takes a dismissable argument which renders the notice dismissable (with the help of JavaScript and localStorage). We show a dismissable notice about a cancelled subscription across the app, but when the user dismisses it, we will start displaying it in the account settings > subscription section instead. So it's either shown across the app, or only on the /settings page. Depending on whether the localStorage flag to dismiss it has been set or not. """ def subscription_cancelled(assigns) def subscription_cancelled( %{ dismissable: true, subscription: %Subscription{status: Subscription.Status.deleted()} } = assigns ) do ~H""" """ end def subscription_cancelled( %{ dismissable: false, subscription: %Subscription{status: Subscription.Status.deleted()} } = assigns ) do assigns = assign(assigns, :container_id, "local-subscription-cancelled-notice") ~H""" """ end def subscription_cancelled(assigns), do: ~H"" attr(:class, :string, default: "") attr(:subscription, :any, default: nil) def subscription_past_due( %{subscription: %Subscription{status: Subscription.Status.past_due()}} = assigns ) do ~H""" """ end def subscription_past_due(assigns), do: ~H"" attr(:class, :string, default: "") attr(:subscription, :any, default: nil) def subscription_paused( %{subscription: %Subscription{status: Subscription.Status.paused()}} = assigns ) do ~H""" """ end def subscription_paused(assigns), do: ~H"" def upgrade_ineligible(assigns) do ~H""" """ end def pending_site_ownerships_notice(%{pending_ownership_count: count} = assigns) do if count > 0 do message = "Your account has been invited to become the owner of " <> if(count == 1, do: "a site, which is", else: "#{count} sites, which are") <> " being counted towards the usage of your account." assigns = assign(assigns, message: message) ~H""" """ else ~H"" end end def growth_grandfathered(assigns) do ~H"""
Your subscription has been grandfathered in at the same rate and terms as when you first joined. If you don't need the "Business" features, you're welcome to stay on this plan. You can adjust the pageview limit or change the billing frequency of this grandfathered plan. If you're interested in business features, you can upgrade to a "Business" plan.
""" end @doc """ Renders a usage notification banner based on the notification type. This is used on the subscription settings page to show contextual notifications about approaching or exceeded limits. """ attr(:type, :atom, required: true) attr(:team, :any, required: true) def usage_notification(assigns) def usage_notification(%{type: :pageview_approaching_limit} = assigns) do ~H""" <.notice title="You're close to your monthly pageview limit" theme={:gray} show_icon={false}>

No action is required. Occasional traffic spikes are normal, and we'll keep tracking your stats as usual. Upgrading now gives you room to grow if higher traffic continues.

<.button_link href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} mt?={false}> Upgrade <.button_link href="https://plausible.io/docs/subscription-plans" theme="secondary" mt?={false} > Learn more
""" end def usage_notification(%{type: :team_member_limit_reached} = assigns) do ~H""" <.notice title="You've reached your current team member limit" theme={:gray} show_icon={false}>

Upgrading lets you add more as your team grows.

<.button_link href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} mt?={false}> Upgrade
""" end def usage_notification(%{type: :site_limit_reached} = assigns) do ~H""" <.notice title="You've reached your current site limit" theme={:gray} show_icon={false}>

Upgrading lets you add more sites as you grow.

<.button_link href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} mt?={false}> Upgrade
""" end def usage_notification(%{type: :site_and_team_member_limit_reached} = assigns) do ~H""" <.notice title="You've reached your current limits for team members and sites" theme={:gray} show_icon={false} >

Upgrading gives you room to grow.

<.button_link href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} mt?={false}> Upgrade
""" end def usage_notification(%{type: :traffic_exceeded_current_cycle} = assigns) do ~H""" <.notice title="Traffic has exceeded your plan limit this cycle" theme={:gray} show_icon={false}>

No action is required. Occasional traffic spikes are normal, but upgrading now gives you room to grow if higher traffic continues.

<.button_link href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} mt?={false}> Upgrade <.button_link href="https://plausible.io/docs/subscription-plans" theme="secondary" mt?={false} > Learn more
""" end def usage_notification(%{type: :traffic_exceeded_last_cycle} = assigns) do ~H""" <.notice title="Traffic exceeded your plan limit last cycle" theme={:gray} show_icon={false}>

No action is required. Occasional traffic spikes are normal, but upgrading now gives you room to grow if higher traffic continues.

<.button_link href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} mt?={false}> Upgrade <.button_link href="https://plausible.io/docs/subscription-plans" theme="secondary" mt?={false} > Learn more
""" end def usage_notification(%{type: :traffic_exceeded_sustained} = assigns) do ~H""" <.notice title="Upgrade required due to sustained higher traffic" theme={:gray} show_icon={false}>

To ensure uninterrupted access to your stats, please upgrade to a plan that fits your current usage.

<.button_link href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} mt?={false}> Upgrade <.button_link href="https://plausible.io/docs/subscription-plans" theme="secondary" mt?={false} > Learn more
""" end def usage_notification(%{type: :manual_lock_grace_period_active} = assigns) do ~H""" <.notice title="You've outgrown your custom plan" theme={:yellow} show_icon={false}>

We'll contact you by email to discuss an updated custom plan based on your current usage.

""" end def usage_notification(%{type: :grace_period_active, team: team} = assigns) do deadline_text = case Plausible.Teams.GracePeriod.expires_in(team) do {0, :hours} -> "within the hour" {1, :hours} -> "within the next hour" {n, :hours} -> "within the next #{n} hours" {n, :days} -> "within the next #{n} days" end assigns = assign(assigns, :deadline_text, deadline_text) ~H""" <.notice title="Upgrade required due to sustained higher traffic" theme={:gray} show_icon={false}>

To ensure uninterrupted access to your stats, please upgrade to a plan that fits your current usage {@deadline_text}.

<.button_link href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} mt?={false}> Upgrade <.button_link href="https://plausible.io/docs/subscription-plans" theme="secondary" mt?={false} > Learn more
""" end def usage_notification(%{type: :dashboard_locked} = assigns) do ~H""" <.notice title="Dashboard access temporarily locked" theme={:gray} show_icon={false}>

Your stats are still being tracked, but dashboard access is temporarily locked because your site exceeded your plan's pageview limit for two consecutive billing cycles. Upgrade to restore access.

<.button_link href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} mt?={false}> Upgrade <.button_link href="https://plausible.io/docs/subscription-plans" theme="secondary" mt?={false} > Learn more
""" end def usage_notification(%{type: :trial_ended} = assigns) do ~H""" <.notice title="Your free trial has ended" theme={:gray} show_icon={false}>

Upgrade to a monthly or yearly plan to continue accessing your sites.

<.button_link id="upgrade-or-change-plan-link" href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} mt?={false} > Choose a plan
""" end def usage_notification(assigns), do: ~H"" defp subscription_cancelled_notice_body(assigns) do ~H"""

You have access to your stats until <%= Calendar.strftime(@subscription.next_bill_date, "%b %-d, %Y") %>. <.link class="underline inline-block" href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)} > Upgrade your subscription to make sure you don't lose access.

<.lose_grandfathering_warning subscription={@subscription} /> """ end defp lose_grandfathering_warning(%{subscription: subscription} = assigns) do plan = Plans.get_regular_plan(subscription, only_non_expired: true) loses_grandfathering? = plan && plan.generation < 5 assigns = assign(assigns, :loses_grandfathering?, loses_grandfathering?) ~H"""

Please also note that by letting your subscription expire, you lose access to our grandfathered terms. If you want to subscribe again after that, your account will be offered the <.link href="https://plausible.io/#pricing" target="_blank" rel="noopener noreferrer" class="underline" >latest pricing.

""" end defp account_label(%Plausible.Teams.Team{setup_complete: true}), do: "This team" defp account_label(_team), do: "This account" end