mirror of
https://github.com/plausible/analytics.git
synced 2024-09-11 18:07:33 +03:00
Notice across the app about Funnels and Revenue goals private preview end (#3510)
* change upgrade CTA notice message for enterprise and business plans * add dismissable option to Generic.notice * more general notice about losing premium features in X days * save notice dismissed per user ... more than one Plausible account can use the same device, so we should scope the fact that the notice has been dismissed by user id. * fix bug applying classes to Generic.notice * apply shadow to the new notice on light mode * use Heroicons.x_mark instead of raw SVG * use Enum.filter instead of list comprehension
This commit is contained in:
parent
0c2e6b8751
commit
fdf1462c04
@ -4,9 +4,10 @@ defmodule PlausibleWeb.Components.Billing do
|
||||
use Phoenix.Component
|
||||
import PlausibleWeb.Components.Generic
|
||||
require Plausible.Billing.Subscription.Status
|
||||
alias Plausible.Billing.Feature.{RevenueGoals, Funnels}
|
||||
alias Plausible.Billing.Feature.{Props, StatsAPI}
|
||||
alias PlausibleWeb.Router.Helpers, as: Routes
|
||||
alias Plausible.Billing.{Subscription, Plans, Subscriptions}
|
||||
alias Plausible.Billing.{Subscription, Plans, Plan, Subscriptions}
|
||||
|
||||
attr(:billable_user, Plausible.Auth.User, required: true)
|
||||
attr(:current_user, Plausible.Auth.User, required: true)
|
||||
@ -17,15 +18,10 @@ defmodule PlausibleWeb.Components.Billing do
|
||||
|
||||
# credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity
|
||||
def premium_feature_notice(assigns) do
|
||||
billable_user = Plausible.Users.with_subscription(assigns.billable_user)
|
||||
plan = Plans.get_regular_plan(billable_user.subscription, only_non_expired: true)
|
||||
business? = plan && plan.kind == :business
|
||||
|
||||
legacy_feature_access? =
|
||||
Timex.before?(assigns.billable_user.inserted_at, Plans.business_tier_launch()) &&
|
||||
assigns.feature_mod in [StatsAPI, Props]
|
||||
|
||||
private_preview? = FunWithFlags.enabled?(:premium_features_private_preview)
|
||||
has_access? = assigns.feature_mod.check_availability(assigns.billable_user) == :ok
|
||||
|
||||
cond do
|
||||
@ -39,14 +35,6 @@ defmodule PlausibleWeb.Components.Billing do
|
||||
</.notice>
|
||||
"""
|
||||
|
||||
private_preview? && !business? ->
|
||||
~H"""
|
||||
<.notice class="rounded-t-md rounded-b-none" size={@size} {@rest}>
|
||||
Business plans are now live! The private preview of <%= @feature_mod.display_name() %> ends <%= private_preview_days_remaining() %>. If you wish to continue using this feature,
|
||||
<.upgrade_call_to_action current_user={@current_user} billable_user={@billable_user} />.
|
||||
</.notice>
|
||||
"""
|
||||
|
||||
not has_access? ->
|
||||
~H"""
|
||||
<.notice class="rounded-t-md rounded-b-none" size={@size} {@rest}>
|
||||
@ -60,7 +48,7 @@ defmodule PlausibleWeb.Components.Billing do
|
||||
end
|
||||
end
|
||||
|
||||
defp private_preview_days_remaining do
|
||||
defp private_preview_end do
|
||||
private_preview_ends_at = Timex.shift(Plausible.Billing.Plans.business_tier_launch(), days: 8)
|
||||
|
||||
days_remaining = Timex.diff(private_preview_ends_at, NaiveDateTime.utc_now(), :day)
|
||||
@ -113,7 +101,7 @@ defmodule PlausibleWeb.Components.Billing do
|
||||
"""
|
||||
|
||||
true ->
|
||||
~H"please contact support@plausible.io about the Enterprise plan"
|
||||
~H"please contact hello@plausible.io to upgrade your subscription"
|
||||
end
|
||||
end
|
||||
|
||||
@ -317,6 +305,48 @@ defmodule PlausibleWeb.Components.Billing do
|
||||
|
||||
def subscription_paused_notice(assigns), do: ~H""
|
||||
|
||||
def private_preview_end_notice(assigns) do
|
||||
user = assigns.user |> Plausible.Users.with_subscription()
|
||||
|
||||
features_to_lose =
|
||||
case Plans.get_subscription_plan(user.subscription) do
|
||||
nil ->
|
||||
[]
|
||||
|
||||
%Plan{kind: :business} ->
|
||||
[]
|
||||
|
||||
_free_10k_or_enterprise_or_growth ->
|
||||
used_features = Plausible.Billing.Quota.features_usage(assigns.user)
|
||||
Enum.filter([Funnels, RevenueGoals], &(&1 in used_features))
|
||||
end
|
||||
|
||||
assigns = assign(assigns, :features_to_lose, features_to_lose)
|
||||
|
||||
~H"""
|
||||
<div
|
||||
:if={FunWithFlags.enabled?(:premium_features_private_preview) && @features_to_lose != []}
|
||||
class="container mt-2"
|
||||
>
|
||||
<.notice
|
||||
class="shadow-md dark:shadow-none"
|
||||
dismissable_id={"premium_features_private_preview_end__#{@user.id}"}
|
||||
>
|
||||
Business plans are now live! The private preview of <%= PlausibleWeb.TextHelpers.pretty_join(
|
||||
Enum.map(@features_to_lose, & &1.display_name())
|
||||
) %> ends <b><%= private_preview_end() %></b>. If you wish to continue using <%= if length(
|
||||
@features_to_lose
|
||||
) == 1,
|
||||
do:
|
||||
"this feature",
|
||||
else:
|
||||
"these features" %>,
|
||||
<.upgrade_call_to_action current_user={@user} billable_user={@user} />.
|
||||
</.notice>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
def present_enterprise_plan(assigns) do
|
||||
~H"""
|
||||
<ul class="w-full py-4">
|
||||
|
@ -60,42 +60,61 @@ defmodule PlausibleWeb.Components.Generic do
|
||||
|
||||
attr(:title, :string, default: "Notice")
|
||||
attr(:size, :atom, default: :sm)
|
||||
attr(:dismissable_id, :any, default: nil)
|
||||
attr(:class, :string, default: "")
|
||||
attr(:rest, :global)
|
||||
slot(:inner_block)
|
||||
|
||||
def notice(assigns) do
|
||||
~H"""
|
||||
<div class="rounded-md bg-yellow-50 dark:bg-yellow-100 p-4" {@rest}>
|
||||
<div class="flex">
|
||||
<div :if={@size !== :xs} class="flex-shrink-0">
|
||||
<svg
|
||||
class="h-5 w-5 text-yellow-400"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3
|
||||
:if={@size !== :xs}
|
||||
class={"text-#{@size} font-medium text-yellow-800 dark:text-yellow-900 mb-2"}
|
||||
>
|
||||
<%= @title %>
|
||||
</h3>
|
||||
<div class={"text-#{@size} text-yellow-700 dark:text-yellow-800"}>
|
||||
<p>
|
||||
<%= render_slot(@inner_block) %>
|
||||
</p>
|
||||
<div id={@dismissable_id} class={@dismissable_id && "hidden"}>
|
||||
<div class={"rounded-md bg-yellow-50 dark:bg-yellow-100 p-4 relative #{@class}"} {@rest}>
|
||||
<button
|
||||
:if={@dismissable_id}
|
||||
class="absolute right-0 top-0 m-2 text-yellow-800 dark:text-yellow-900"
|
||||
onclick={"localStorage['notice_dismissed__#{@dismissable_id}'] = 'true'; document.getElementById('#{@dismissable_id}').classList.add('hidden')"}
|
||||
>
|
||||
<Heroicons.x_mark class="h-4 w-4 hover:stroke-2" />
|
||||
</button>
|
||||
<div class="flex">
|
||||
<div :if={@size !== :xs} class="flex-shrink-0">
|
||||
<svg
|
||||
class="h-5 w-5 text-yellow-400"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3
|
||||
:if={@size !== :xs}
|
||||
class={"text-#{@size} font-medium text-yellow-800 dark:text-yellow-900 mb-2"}
|
||||
>
|
||||
<%= @title %>
|
||||
</h3>
|
||||
<div class={"text-#{@size} text-yellow-700 dark:text-yellow-800"}>
|
||||
<p>
|
||||
<%= render_slot(@inner_block) %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script data-key={@dismissable_id}>
|
||||
const dismissId = document.currentScript.dataset.key
|
||||
const localStorageKey = `notice_dismissed__${dismissId}`
|
||||
|
||||
if (localStorage[localStorageKey] !== 'true') {
|
||||
document.getElementById(dismissId).classList.remove('hidden')
|
||||
}
|
||||
</script>
|
||||
"""
|
||||
end
|
||||
|
||||
|
@ -95,12 +95,16 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<.subscription_past_due_notice
|
||||
subscription={@conn.assigns[:current_user] && @conn.assigns[:current_user].subscription}
|
||||
class="container"
|
||||
/>
|
||||
<%= if @conn.assigns[:current_user] do %>
|
||||
<.subscription_past_due_notice
|
||||
subscription={@conn.assigns.current_user.subscription}
|
||||
class="container"
|
||||
/>
|
||||
|
||||
<.subscription_paused_notice
|
||||
subscription={@conn.assigns[:current_user] && @conn.assigns[:current_user].subscription}
|
||||
class="container"
|
||||
/>
|
||||
<.subscription_paused_notice
|
||||
subscription={@conn.assigns.current_user.subscription}
|
||||
class="container"
|
||||
/>
|
||||
|
||||
<.private_preview_end_notice user={@conn.assigns.current_user} />
|
||||
<% end %>
|
||||
|
@ -120,7 +120,7 @@ defmodule PlausibleWeb.Components.BillingTest do
|
||||
)
|
||||
|
||||
assert rendered =~ "Your account is limited to 10 users."
|
||||
assert rendered =~ "please contact support@plausible.io about the Enterprise plan"
|
||||
assert rendered =~ "please contact hello@plausible.io to upgrade your subscription"
|
||||
end
|
||||
|
||||
test "limit_exceeded_notice/1 when billable user is on a business plan displays support email" do
|
||||
@ -135,6 +135,6 @@ defmodule PlausibleWeb.Components.BillingTest do
|
||||
)
|
||||
|
||||
assert rendered =~ "Your account is limited to 10 users."
|
||||
assert rendered =~ "please contact support@plausible.io about the Enterprise plan"
|
||||
assert rendered =~ "please contact hello@plausible.io to upgrade your subscription"
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user