Add data retention to the choose plan page (#3605)

* Add data retention field to plans

* Display data retention as benefit when choosing plan

* Split fields in two module attributes

* Remove extra whitespace

Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>

---------

Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
This commit is contained in:
Vinicius Brasil 2023-12-12 08:19:54 -03:00 committed by GitHub
parent 26809bfd2e
commit 45a763ab2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 90 additions and 38 deletions

View File

@ -23,6 +23,7 @@ defmodule Plausible.Billing.Plan do
field :site_limit, :integer
field :team_member_limit, Plausible.Billing.Ecto.Limit
field :volume, :string
field :data_retention_in_years, :integer
field :monthly_cost
field :monthly_product_id, :string
@ -30,16 +31,16 @@ defmodule Plausible.Billing.Plan do
field :yearly_product_id, :string
end
@fields ~w(generation kind features monthly_pageview_limit site_limit team_member_limit volume monthly_cost monthly_product_id yearly_cost yearly_product_id)a
@required_fields ~w(generation kind features monthly_pageview_limit site_limit team_member_limit volume)a
@optional_fields ~w(monthly_cost yearly_cost monthly_product_id yearly_product_id data_retention_in_years)a
@fields @required_fields ++ @optional_fields
def changeset(plan, attrs) do
plan
|> cast(attrs, @fields)
|> put_volume()
|> validate_required_either([:monthly_product_id, :yearly_product_id])
|> validate_required(
@fields -- [:monthly_cost, :yearly_cost, :monthly_product_id, :yearly_product_id]
)
|> validate_required(@required_fields)
end
defp put_volume(changeset) do
@ -51,9 +52,10 @@ defmodule Plausible.Billing.Plan do
end
def validate_required_either(changeset, fields) do
if Enum.any?(fields, &get_field(changeset, &1)),
do: changeset,
else:
add_error(changeset, hd(fields), "one of these fields must be present #{inspect(fields)}")
if Enum.any?(fields, &get_field(changeset, &1)) do
changeset
else
add_error(changeset, hd(fields), "one of these fields must be present #{inspect(fields)}")
end
end
end

View File

@ -739,29 +739,34 @@ defmodule PlausibleWeb.Live.ChoosePlan do
[
team_member_limit_benefit(plan),
site_limit_benefit(plan),
data_retention_benefit(plan),
"Intuitive, fast and privacy-friendly dashboard",
"Email/Slack reports",
"Google Analytics import"
]
|> Kernel.++(feature_benefits(plan))
|> Enum.filter(& &1)
end
defp business_benefits(plan, growth_benefits) do
[
"Everything in Growth",
team_member_limit_benefit(plan),
site_limit_benefit(plan)
site_limit_benefit(plan),
data_retention_benefit(plan)
]
|> Kernel.++(feature_benefits(plan))
|> Kernel.--(growth_benefits)
|> Kernel.++(["Priority support"])
|> Enum.filter(& &1)
end
defp enterprise_benefits(business_benefits) do
team_members =
if "Up to 10 team members" in business_benefits,
do: "10+ team members",
else: nil
if "Up to 10 team members" in business_benefits, do: "10+ team members"
data_retention =
if "5 years of data retention" in business_benefits, do: "5+ years of data retention"
[
"Everything in Business",
@ -769,11 +774,16 @@ defmodule PlausibleWeb.Live.ChoosePlan do
"50+ sites",
"600+ Stats API requests per hour",
&sites_api_benefit/1,
data_retention,
"Technical onboarding"
]
|> Enum.filter(& &1)
end
defp data_retention_benefit(%Plan{} = plan) do
if plan.data_retention_in_years, do: "#{plan.data_retention_in_years} years of data retention"
end
defp team_member_limit_benefit(%Plan{} = plan) do
case plan.team_member_limit do
:unlimited -> "Unlimited team members"

View File

@ -7,7 +7,8 @@
"yearly_product_id":"857079",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -17,7 +18,8 @@
"yearly_product_id":"857080",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -27,7 +29,8 @@
"yearly_product_id":"857081",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -37,7 +40,8 @@
"yearly_product_id":"857082",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -47,7 +51,8 @@
"yearly_product_id":"857083",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -57,7 +62,8 @@
"yearly_product_id":"857084",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -67,7 +73,8 @@
"yearly_product_id":"857085",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -77,7 +84,8 @@
"yearly_product_id":"857086",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"business",
@ -87,7 +95,8 @@
"yearly_product_id":"857087",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props","revenue_goals","funnels","stats_api"]
"features":["goals","props","revenue_goals","funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -97,7 +106,8 @@
"yearly_product_id":"857088",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props","revenue_goals","funnels","stats_api"]
"features":["goals","props","revenue_goals","funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -107,7 +117,8 @@
"yearly_product_id":"857089",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props","revenue_goals","funnels","stats_api"]
"features":["goals","props","revenue_goals","funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -117,7 +128,8 @@
"yearly_product_id":"857090",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props","revenue_goals","funnels","stats_api"]
"features":["goals","props","revenue_goals","funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -127,7 +139,8 @@
"yearly_product_id":"857091",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props","revenue_goals","funnels","stats_api"]
"features":["goals","props","revenue_goals","funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -137,7 +150,8 @@
"yearly_product_id":"857092",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props","revenue_goals","funnels","stats_api"]
"features":["goals","props","revenue_goals","funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -147,7 +161,8 @@
"yearly_product_id":"857093",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props","revenue_goals","funnels","stats_api"]
"features":["goals","props","revenue_goals","funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -157,6 +172,7 @@
"yearly_product_id":"857094",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props","revenue_goals","funnels","stats_api"]
"features":["goals","props","revenue_goals","funnels","stats_api"],
"data_retention_in_years": 5
}
]

View File

@ -0,0 +1,11 @@
defmodule Plausible.Repo.Migrations.AddDataRetentionInYearsToPlans do
use Ecto.Migration
def change do
if !Application.get_env(:plausible, :is_selfhost) do
alter table(:plans) do
add :data_retention_in_years, :integer, null: true
end
end
end
end

View File

@ -37,7 +37,8 @@
"yearly_product_id":"63862",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -47,7 +48,8 @@
"yearly_product_id":"63863",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -57,7 +59,8 @@
"yearly_product_id":"63864",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -67,7 +70,8 @@
"yearly_product_id":"63865",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"growth",
@ -77,7 +81,8 @@
"yearly_product_id":"63866",
"site_limit":10,
"team_member_limit":3,
"features":["goals"]
"features":["goals"],
"data_retention_in_years": 3
},
{
"kind":"business",
@ -117,7 +122,8 @@
"yearly_product_id":"63870",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props", "revenue_goals", "funnels","stats_api"]
"features":["goals","props", "revenue_goals", "funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -127,7 +133,8 @@
"yearly_product_id":"63871",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props", "revenue_goals", "funnels","stats_api"]
"features":["goals","props", "revenue_goals", "funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -137,7 +144,8 @@
"yearly_product_id":"63872",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props", "revenue_goals", "funnels","stats_api"]
"features":["goals","props", "revenue_goals", "funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -147,7 +155,8 @@
"yearly_product_id":"63873",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props", "revenue_goals", "funnels","stats_api"]
"features":["goals","props", "revenue_goals", "funnels","stats_api"],
"data_retention_in_years": 5
},
{
"kind":"business",
@ -157,6 +166,7 @@
"yearly_product_id":"63874",
"site_limit":50,
"team_member_limit":10,
"features":["goals","props", "revenue_goals", "funnels","stats_api"]
"features":["goals","props", "revenue_goals", "funnels","stats_api"],
"data_retention_in_years": 5
}
]

View File

@ -262,6 +262,7 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
assert growth_box =~ "Email/Slack reports"
assert growth_box =~ "Google Analytics import"
assert growth_box =~ "Goals and custom events"
assert growth_box =~ "3 years of data retention"
assert business_box =~ "Everything in Growth"
assert business_box =~ "Up to 10 team members"
@ -271,6 +272,7 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
assert business_box =~ "Funnels"
assert business_box =~ "Ecommerce revenue attribution"
assert business_box =~ "Priority support"
assert business_box =~ "5 years of data retention"
refute business_box =~ "Goals and custom events"
@ -280,6 +282,7 @@ defmodule PlausibleWeb.Live.ChoosePlanTest do
assert enterprise_box =~ "600+ Stats API requests per hour"
assert enterprise_box =~ "Sites API access for"
assert enterprise_box =~ "Technical onboarding"
assert enterprise_box =~ "5+ years of data retention"
assert text_of_attr(find(doc, "#{@enterprise_plan_box} p a"), "href") =~
"https://plausible.io/white-label-web-analytics"