analytics/lib/plausible_web/templates/billing/upgrade.html.eex

129 lines
6.8 KiB
Elixir
Raw Normal View History

2021-05-13 11:59:33 +03:00
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/fetch-jsonp/1.1.3/fetch-jsonp.min.js"></script>
<script>
2021-05-13 11:59:33 +03:00
plans = function() {
return {
Use Phoenix LiveView for the upgrade page (#3382) * add a new upgrade page liveview behind a FF * Create plans_v4.json file * Add the upgrade page UI template and some basic functionalities * different content based on subscription plan existing or not * pageview slider * monthly/yearly switch * fix tests * split into 2 separate functions * rename variables * implement volume slider + read default interval/volume from plan * organize choose-plan.ex better * remove unused vars from tests * make monthly_cost and yearly_cost nil by default The actual prices for all plans are stored in Paddle. We don't need to keep the duplicates in the JSON files. * add fetch_prices/1 to PaddleApi * make v4 business ID's differ from growth ones * render actual price information from plans ...and make the prices in both growth and business plan boxes change dynamically when the pageview slider or interval is changed. * highlight current subscription plan box * add test describe block for business tier subscription * connect to live socket only on the specific LV page using focus.html * only wrap the input slider inside the form * little readability improvement * add v4 team_member_limits (after rebase with master) * extract monthly_quota_box function in user_settings When the business_tier FF is enabled, this section is different and links to the new upgrade page. * document subscription statuses * change _notice.html.eex to .heex * extract subscription status notice components * add failed payment notices to upgrade page * create class_of_element/2 convenience function for testing * add cancel_subscription mix task * implement checkout buttons * mix format * get all available plans with prices through plans.ex * use more suitable function for fetching usage * avoid double db lookups on mount * rename variable * separate functions for getting plan by product_id vs subscription * separate subscription status docs into context module * consider cancelled subscriptions * default volume by usage if no subscription plan * add enterprise-level volume option to slider * optimize for darkmode * UI improvements * display 2 months free notice for yearly billing * VAT excluded notice * note about having a business subscription in user settings * make the page pop and fit plans on screen on first render * optimize for mobile and remove background containers * change default price tag to simply 'N/A' * fix tests * Change Paddle.js integration to use JavaScript directly * rename many variables * allow users on v1 and v2 plan subscribe to 20M and 50M tiers * add a test for two months free label * make it work with a free_10k subscription * small test improvement and formatting * change other upgrade link in user settings if FF enabled * dialyzer * fix typo * add test for free_10k user * silence credo * mix format * credo - add moduledoc * credo - another moduledoc * handle calls to sentry on the api level * refactor getting regular subscription plan for LiveView * post review code style tweaks * remove unused aliases * credo - add @moduledoc false to Subscriptions * crash in cancel_subscription task when Repo update fails * readability improvements (review suggestions) * add comment about 'external_resource' module attr --------- Co-authored-by: Vinicius Brasil <vini@hey.com>
2023-10-03 13:36:22 +03:00
rawPlans: <%= raw Jason.encode!(Plausible.Billing.Plans.growth_plans_for(@user)) %>,
2021-05-13 11:59:33 +03:00
localizedPlans: null,
volume: '10k',
billingCycle: 'monthly',
selectedPlanPrice() {
2021-05-13 11:59:33 +03:00
return this.priceFor(this.selectedPlanProductId())
},
selectedPlanProductId() {
var selectedPlan = this.rawPlans.find((plan) => plan.volume === this.volume)
if (this.billingCycle === 'monthly'){
return selectedPlan.monthly_product_id
} else {
return selectedPlan.yearly_product_id
}
2021-05-13 11:59:33 +03:00
},
priceFor(productId) {
var plan = this.localizedPlans.find(plan => plan.product_id === Number(productId))
var currency = {
'USD': '$',
'EUR': '',
'GBP': '£'
}[plan.currency]
2021-05-14 10:50:56 +03:00
return currency + plan.price.net
2021-05-13 11:59:33 +03:00
},
fetchPlans() {
var productIds = []
2021-05-13 12:16:31 +03:00
this.rawPlans.forEach((plan) => {
2021-05-13 11:59:33 +03:00
productIds.push(plan.monthly_product_id)
productIds.push(plan.yearly_product_id)
})
2021-12-28 13:26:53 +03:00
var checkoutDomain = '<%= Plausible.Billing.PaddleApi.checkout_domain() %>'
fetchJsonp(checkoutDomain + '/api/2.0/prices?product_ids=' + productIds.join(','))
2021-05-13 11:59:33 +03:00
.then((res) => res.json())
.then((data) => {
this.localizedPlans = data.response.products
})
}
}
}
</script>
2019-09-02 14:29:19 +03:00
<div class="mx-auto mt-6 text-center">
<h1 class="text-3xl font-black dark:text-gray-100">Upgrade your free trial</h1>
</div>
<div>
2021-01-19 11:36:02 +03:00
<div class="flex flex-col w-full max-w-4xl px-4 mx-auto mt-4 md:flex-row">
2021-05-13 11:59:33 +03:00
<div x-init="fetchPlans()" x-data="window.plans()" class="flex-1 px-8 py-4 mt-8 mb-4 bg-white rounded shadow-md dark:bg-gray-800">
<div class="w-full py-4 dark:text-gray-100">
<span>You've used <b><%= PlausibleWeb.AuthView.delimit_integer(@usage) %></b> billable pageviews in the last 30 days</span>
</div>
<div class="pt-2"></div>
2019-09-02 14:29:19 +03:00
2021-01-19 11:36:02 +03:00
<span class="relative z-0 inline-flex w-full shadow-sm">
<button type="button" @click="billingCycle = 'monthly'" :class="{'bg-indigo-600 text-white border-indigo-600': billingCycle === 'monthly', 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:text-gray-500 dark:hover:text-gray-200 border-gray-300 dark:border-gray-500': billingCycle === 'yearly'}" class="relative w-full px-4 py-2 text-sm font-medium text-center border rounded-l-md leading-5 focus:outline-none focus:border-blue-300 focus:ring transition ease-in-out duration-150">
Monthly billing
</button>
2021-01-19 11:36:02 +03:00
<button type="button" @click="billingCycle = 'yearly'" :class="{'bg-indigo-600 text-white border-indigo-600': billingCycle === 'yearly', 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:text-gray-500 dark:hover:text-gray-200 border-gray-300 dark:border-gray-500': billingCycle === 'monthly'}" class="relative w-full px-4 py-2 -ml-px text-sm font-medium text-center border rounded-r-md leading-5 focus:outline-none focus:border-blue-300 focus:ring transition ease-in-out duration-150">
Yearly billing
</button>
</span>
<div class="pt-6"></div>
2021-05-13 11:59:33 +03:00
<template x-if="localizedPlans" class="flex flex-col">
2021-01-19 11:36:02 +03:00
<div class="py-2 -my-2 overflow-x-auto sm:-mx-6 sm:px-6 lg:-mx-8 lg:px-8">
<div class="inline-block min-w-full overflow-hidden align-middle border-b border-gray-200 shadow sm:rounded-lg dark:border-t dark:border-l dark:border-r dark:shadow-none">
<table class="min-w-full">
<thead>
<tr>
2021-01-19 11:36:02 +03:00
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase bg-gray-100 border-b border-gray-200 dark:bg-gray-900 leading-4 dark:text-gray-200">
Monthly pageviews
</th>
2021-01-19 11:36:02 +03:00
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase bg-gray-100 border-b border-gray-200 dark:bg-gray-900 leading-4 dark:text-gray-200">
Price
</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-800">
Use Phoenix LiveView for the upgrade page (#3382) * add a new upgrade page liveview behind a FF * Create plans_v4.json file * Add the upgrade page UI template and some basic functionalities * different content based on subscription plan existing or not * pageview slider * monthly/yearly switch * fix tests * split into 2 separate functions * rename variables * implement volume slider + read default interval/volume from plan * organize choose-plan.ex better * remove unused vars from tests * make monthly_cost and yearly_cost nil by default The actual prices for all plans are stored in Paddle. We don't need to keep the duplicates in the JSON files. * add fetch_prices/1 to PaddleApi * make v4 business ID's differ from growth ones * render actual price information from plans ...and make the prices in both growth and business plan boxes change dynamically when the pageview slider or interval is changed. * highlight current subscription plan box * add test describe block for business tier subscription * connect to live socket only on the specific LV page using focus.html * only wrap the input slider inside the form * little readability improvement * add v4 team_member_limits (after rebase with master) * extract monthly_quota_box function in user_settings When the business_tier FF is enabled, this section is different and links to the new upgrade page. * document subscription statuses * change _notice.html.eex to .heex * extract subscription status notice components * add failed payment notices to upgrade page * create class_of_element/2 convenience function for testing * add cancel_subscription mix task * implement checkout buttons * mix format * get all available plans with prices through plans.ex * use more suitable function for fetching usage * avoid double db lookups on mount * rename variable * separate functions for getting plan by product_id vs subscription * separate subscription status docs into context module * consider cancelled subscriptions * default volume by usage if no subscription plan * add enterprise-level volume option to slider * optimize for darkmode * UI improvements * display 2 months free notice for yearly billing * VAT excluded notice * note about having a business subscription in user settings * make the page pop and fit plans on screen on first render * optimize for mobile and remove background containers * change default price tag to simply 'N/A' * fix tests * Change Paddle.js integration to use JavaScript directly * rename many variables * allow users on v1 and v2 plan subscribe to 20M and 50M tiers * add a test for two months free label * make it work with a free_10k subscription * small test improvement and formatting * change other upgrade link in user settings if FF enabled * dialyzer * fix typo * add test for free_10k user * silence credo * mix format * credo - add moduledoc * credo - another moduledoc * handle calls to sentry on the api level * refactor getting regular subscription plan for LiveView * post review code style tweaks * remove unused aliases * credo - add @moduledoc false to Subscriptions * crash in cancel_subscription task when Repo update fails * readability improvements (review suggestions) * add comment about 'external_resource' module attr --------- Co-authored-by: Vinicius Brasil <vini@hey.com>
2023-10-03 13:36:22 +03:00
<%= for plan <- Plausible.Billing.Plans.growth_plans_for(@user) do %>
2021-05-13 11:59:33 +03:00
<%= render("_plan_option.html", plan: plan) %>
<% end %>
</tbody>
</table>
</div>
</div>
2021-05-13 11:59:33 +03:00
</template>
<div x-show="!localizedPlans" class="mx-auto my-56 loading sm"><div></div></div>
2021-01-19 11:36:02 +03:00
<div class="mt-6 text-right">
2021-05-13 12:16:31 +03:00
<div class="text-sm font-medium dark:text-gray-100">Due today: <template x-if="localizedPlans"><b x-text="selectedPlanPrice()"></b></template></div>
2021-05-12 14:07:20 +03:00
<div class="mb-4 text-xs font-medium dark:text-gray-100">+ VAT if applicable</div>
<span class="inline-flex rounded-md shadow-sm">
Refactor enterprise plan upgrade and change-plan actions (#3397) * rename enterprise?/1 function * change link text to Upgrade when subscription deleted * extract paddle_button and paddle_script components * create a new upgrade-to-enterprise-plan page * extract upgrade_link component * rename function * link to enterprise plan upgrade page from settings ...if the user has an enterprise plan configured * fetch enterprise plan price on the new page * add change_enterprise_plan functionality on the new page * render existing change_enterprise_plan_contact_us.html ...when subscribed to latest configured enterprise plan * rename vars and extract resumable? fn * remove dead billing route * small test refactor: extract convenience fn * add tests for... ...restricting paused and past_due subscription access to the new enterprise plan page. 1. redirect to /settings from the controller action 2. hiding the change-plan link from the user settings * implement redirect to /settings * hide the enterprise upgrade/change-plan link * add tests for a deleted enterprise subscription * plug in the new controller action and delete dead code * optimize for dark mode * fix compile warning * credo fix * display N/A instead of crash when price nil * change subscription.status type to Ecto.Enum Also, create a new `Subscription.Status` module that exposes macros to return the used atom values (prevent typos at compiletime). * fix bug (@conn not available anymore) * use Routes.billing_path where applicable * add a status() type * silence credo * refactor suggestion from review Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com> * Remove the __using__ macro from Subscription.Status ... instead be explicit about requires and aliases and also order the use, import, require, and alias clauses according to https://github.com/christopheradams/elixir_style_guide#module-attribute-ordering * drop the virtual Enteprise 'price_per_interval' field * apply review suggestion to make the code more DRY * use dot syntax to fetch current user in new controller actions * fix formatting --------- Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
2023-10-10 20:35:17 +03:00
<button type="button" data-theme="none" :data-product="selectedPlanProductId()" data-email="<%= @conn.assigns[:current_user].email %>" data-disable-logout="true" data-passthrough="<%= @conn.assigns[:current_user].id %>" data-success="<%= Routes.billing_path(@conn, :upgrade_success) %>" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent paddle_button leading-5 rounded-md hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:ring active:bg-indigo-700 transition ease-in-out duration-150">
2021-01-19 11:36:02 +03:00
<svg fill="currentColor" viewBox="0 0 20 20" class="inline w-4 h-4 mr-2"><path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"></path></svg>
Pay securely via Paddle
</button>
</span>
</div>
</div>
2019-09-02 14:29:19 +03:00
2021-01-19 11:36:02 +03:00
<div class="flex-1 pl-8 pt-14">
<h3 class="text-lg font-medium text-gray-900 leading-6 dark:text-gray-100">
What happens if I go over my page views limit?
</h3>
2021-01-19 11:36:02 +03:00
<div class="mt-2 text-base text-gray-500 leading-6 dark:text-gray-200">
You will never be charged extra for an occasional traffic spike. There are no surprise fees and your card will never be charged unexpectedly.<br /><br />
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.
</div>
2019-09-02 14:29:19 +03:00
</div>
</div>
2019-09-02 14:29:19 +03:00
</div>
2021-01-19 11:36:02 +03:00
<div class="mt-8 text-center dark:text-gray-100">
Questions? <%= link("Contact us", to: "https://plausible.io/contact", class: "text-indigo-500") %>
</div>
<%= render("_paddle_script.html") %>