defmodule PlausibleWeb.Live.ChoosePlan do @moduledoc """ LiveView for upgrading to a plan, or changing an existing plan. """ use PlausibleWeb, :live_view use Phoenix.HTML require Plausible.Billing.Subscription.Status alias PlausibleWeb.Components.Billing.{PlanBox, PlanBenefits, Notice, PageviewSlider} alias Plausible.Site alias Plausible.Users alias Plausible.Billing.{Plans, Quota} @contact_link "https://plausible.io/contact" @billing_faq_link "https://plausible.io/docs/billing" def mount(_params, %{"current_user_id" => user_id, "remote_ip" => remote_ip}, socket) do socket = socket |> assign_new(:user, fn -> Users.with_subscription(user_id) end) |> assign_new(:pending_ownership_site_ids, fn %{user: user} -> user.email |> Site.Memberships.all_pending_ownerships() |> Enum.map(& &1.site_id) end) |> assign_new(:usage, fn %{ user: user, pending_ownership_site_ids: pending_ownership_site_ids } -> Quota.Usage.usage(user, with_features: true, pending_ownership_site_ids: pending_ownership_site_ids ) end) |> assign_new(:owned_plan, fn %{user: %{subscription: subscription}} -> Plans.get_regular_plan(subscription, only_non_expired: true) end) |> assign_new(:owned_tier, fn %{owned_plan: owned_plan} -> if owned_plan, do: Map.get(owned_plan, :kind), else: nil end) |> assign_new(:current_interval, fn %{user: user} -> current_user_subscription_interval(user.subscription) end) |> assign_new(:available_plans, fn %{user: user} -> Plans.available_plans_for(user, with_prices: true, customer_ip: remote_ip) end) |> assign_new(:recommended_tier, fn %{usage: usage, available_plans: available_plans} -> highest_growth_plan = List.last(available_plans.growth) highest_business_plan = List.last(available_plans.business) Quota.suggest_tier(usage, highest_growth_plan, highest_business_plan) end) |> assign_new(:available_volumes, fn %{available_plans: available_plans} -> get_available_volumes(available_plans) end) |> assign_new(:selected_volume, fn %{ usage: usage, available_volumes: available_volumes } -> default_selected_volume(usage.monthly_pageviews, available_volumes) end) |> assign_new(:selected_interval, fn %{current_interval: current_interval} -> current_interval || :monthly end) |> assign_new(:selected_growth_plan, fn %{ available_plans: available_plans, selected_volume: selected_volume } -> get_plan_by_volume(available_plans.growth, selected_volume) end) |> assign_new(:selected_business_plan, fn %{ available_plans: available_plans, selected_volume: selected_volume } -> get_plan_by_volume(available_plans.business, selected_volume) end) {:ok, socket} end def render(assigns) do growth_plan_to_render = assigns.selected_growth_plan || List.last(assigns.available_plans.growth) business_plan_to_render = assigns.selected_business_plan || List.last(assigns.available_plans.business) growth_benefits = PlanBenefits.for_growth(growth_plan_to_render) business_benefits = PlanBenefits.for_business(business_plan_to_render, growth_benefits) enterprise_benefits = PlanBenefits.for_enterprise(business_benefits) assigns = assigns |> assign(:growth_plan_to_render, growth_plan_to_render) |> assign(:business_plan_to_render, business_plan_to_render) |> assign(:growth_benefits, growth_benefits) |> assign(:business_benefits, business_benefits) |> assign(:enterprise_benefits, enterprise_benefits) ~H"""

<%= if @owned_plan, do: "Change subscription plan", else: "Upgrade your account" %>

<.interval_picker selected_interval={@selected_interval} />

<.render_usage pageview_usage={@usage.monthly_pageviews} />

<.pageview_limit_notice :if={!@owned_plan} /> <.help_links />
""" end defp render_usage(assigns) do case assigns.pageview_usage do %{last_30_days: _} -> ~H""" You have used <%= PlausibleWeb.AuthView.delimit_integer(@pageview_usage.last_30_days.total) %> billable pageviews in the last 30 days """ %{last_cycle: _} -> ~H""" You have used <%= PlausibleWeb.AuthView.delimit_integer(@pageview_usage.last_cycle.total) %> billable pageviews in the last billing cycle """ end end def handle_event("set_interval", %{"interval" => interval}, socket) do new_interval = case interval do "yearly" -> :yearly "monthly" -> :monthly end {:noreply, assign(socket, selected_interval: new_interval)} end def handle_event("slide", %{"slider" => index}, socket) do index = String.to_integer(index) %{available_plans: available_plans, available_volumes: available_volumes} = socket.assigns new_volume = if index == length(available_volumes) do :enterprise else Enum.at(available_volumes, index) end {:noreply, assign(socket, selected_volume: new_volume, selected_growth_plan: get_plan_by_volume(available_plans.growth, new_volume), selected_business_plan: get_plan_by_volume(available_plans.business, new_volume) )} end defp default_selected_volume(pageview_usage, available_volumes) do total = case pageview_usage do %{last_30_days: usage} -> usage.total %{last_cycle: usage} -> usage.total end Enum.find(available_volumes, &(total < &1)) || :enterprise end defp current_user_subscription_interval(subscription) do case Plans.subscription_interval(subscription) do "yearly" -> :yearly "monthly" -> :monthly _ -> nil end end defp get_plan_by_volume(_, :enterprise), do: nil defp get_plan_by_volume(plans, volume) do Enum.find(plans, &(&1.monthly_pageview_limit == volume)) end defp interval_picker(assigns) do ~H"""
<.two_months_free />
""" end def two_months_free(assigns) do ~H""" 2 months free """ end defp pageview_limit_notice(assigns) do ~H"""

What happens if I go over my page views limit?

You will never be charged extra for an occasional traffic spike. There are no surprise fees and your card will never be charged unexpectedly. If your page views exceed your plan for two consecutive months, we will contact you to upgrade to a higher plan for the following month. You will have two weeks to make a decision. You can decide to continue with a higher plan or to cancel your account at that point.
""" end defp help_links(assigns) do ~H"""
Questions? Contact us or see billing FAQ
""" end defp get_available_volumes(%{business: business_plans, growth: growth_plans}) do growth_volumes = Enum.map(growth_plans, & &1.monthly_pageview_limit) business_volumes = Enum.map(business_plans, & &1.monthly_pageview_limit) (growth_volumes ++ business_volumes) |> Enum.uniq() end defp contact_link(), do: @contact_link defp billing_faq_link(), do: @billing_faq_link end