1
0
Fork 0
mirror of synced 2024-08-26 23:42:06 +12:00

Billing and usage page updates to support different kinds of users and plans

This commit is contained in:
Rory Powell 2022-09-01 11:36:23 +01:00
parent bbbf8bfc0b
commit ba5ed65e03
3 changed files with 100 additions and 151 deletions

View file

@ -1,6 +1,6 @@
<script>
import { Body, ProgressBar, Heading, Icon, Link } from "@budibase/bbui"
import { admin } from "../../stores/portal"
import { admin, auth } from "../../stores/portal"
import { onMount } from "svelte"
export let usage
export let warnWhenFull = false
@ -9,6 +9,8 @@
let unlimited = false
let showWarning = false
$: accountPortalAccess = $auth?.user?.accountPortalAccess
const isUnlimited = () => {
if (usage.total === -1) {
return true
@ -66,7 +68,12 @@
{/if}
{#if showWarning}
<Body size="S">
To get more queries <Link href={upgradeUrl}>upgrade your plan</Link>
To get more {usage.name.toLowerCase()}
{#if accountPortalAccess}
<Link href={upgradeUrl}>upgrade your plan</Link>
{:else}
contact your account holder
{/if}
</Body>
{/if}
</div>

View file

@ -3,12 +3,11 @@
export let description = ""
export let title = ""
export let subtitle = ""
export let primaryAction
export let secondaryAction
export let primaryActionText
export let secondaryActionText
export let primaryCta = false
export let primaryCta = true
export let textRows = []
$: primaryDefined = primaryAction && primaryActionText
@ -23,14 +22,13 @@
<Detail size="M">{description}</Detail>
</div>
<Heading size="M">{title}</Heading>
<div class="dash-card-title">
<Detail size="M">{subtitle}</Detail>
</div>
<div class="text-rows">
{#each textRows as row}
<Body>{row}</Body>
{/each}
</div>
{#if textRows.length}
<div class="text-rows">
{#each textRows as row}
<Body>{row}</Body>
{/each}
</div>
{/if}
</Layout>
</div>
<div class="header-actions">

View file

@ -5,8 +5,8 @@
Heading,
Layout,
notifications,
Page,
Detail,
Link,
} from "@budibase/bbui"
import { onMount } from "svelte"
import { admin, auth, licensing } from "../../../../stores/portal"
@ -15,29 +15,20 @@
let staticUsage = []
let monthlyUsage = []
let price
let lastPayment
let cancelAt
let nextPayment
let balance
let loaded = false
let textRows = []
let daysRemainingInMonth
let primaryActionText
const upgradeUrl = `${$admin.accountPortalUrl}/portal/upgrade`
const manageUrl = `${$admin.accountPortalUrl}/portal/billing`
const warnUsage = ["Queries", "Automations", "Rows"]
const warnUsage = ["Queries", "Automations", "Rows", "Day Passes"]
$: quotaUsage = $licensing.quotaUsage
$: license = $auth.user?.license
const numberFormatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 0,
maximumFractionDigits: 0,
})
$: accountPortalAccess = $auth?.user?.accountPortalAccess
const setMonthlyUsage = () => {
monthlyUsage = []
@ -71,49 +62,8 @@
staticUsage = staticUsage.sort((a, b) => a.name.localeCompare(b.name))
}
const setNextPayment = () => {
const periodEnd = license?.billing.subscription?.currentPeriodEnd
const cancelAt = license?.billing.subscription?.cancelAt
if (periodEnd) {
if (cancelAt && periodEnd <= cancelAt) {
return
}
nextPayment = `Next payment: ${getLocaleDataString(periodEnd)}`
}
}
const setCancelAt = () => {
cancelAt = license?.billing.subscription?.cancelAt
}
const setLastPayment = () => {
const periodStart = license?.billing.subscription?.currentPeriodStart
if (periodStart) {
lastPayment = `Last payment: ${getLocaleDataString(periodStart)}`
}
}
const setBalance = () => {
const customerBalance = license?.billing.customer.balance
if (customerBalance) {
balance = `Balance: ${numberFormatter.format(
(customerBalance / 100) * -1
)}`
}
}
const getLocaleDataString = epoch => {
const date = new Date(epoch * 1000)
return date.toLocaleDateString("default", {
day: "numeric",
month: "long",
year: "numeric",
})
}
const setPrice = () => {
const planPrice = license.plan.price
price = `${numberFormatter.format(planPrice.amountMonthly / 100)} per month`
cancelAt = license?.billing?.subscription?.cancelAt
}
const capitalise = string => {
@ -126,10 +76,6 @@
return capitalise(license?.plan.type)
}
const planSubtitle = () => {
return `${license?.plan.price.sessions} day passes`
}
const getDaysRemaining = timestamp => {
if (!timestamp) {
return
@ -153,16 +99,6 @@
if (cancelAt) {
textRows.push("Subscription has been cancelled")
textRows.push(`${getDaysRemaining(cancelAt * 1000)} days remaining`)
} else {
if (price) {
textRows.push(price)
}
if (lastPayment) {
textRows.push(lastPayment)
}
if (nextPayment) {
textRows.push(nextPayment)
}
}
}
@ -185,6 +121,19 @@
}
}
const setPrimaryActionText = () => {
if (license?.plan.type === PlanType.FREE) {
primaryActionText = "Upgrade"
return
}
if (cancelAt) {
primaryActionText = "Renew"
} else {
primaryActionText = "Manage"
}
}
const init = async () => {
try {
await licensing.getQuotaUsage()
@ -201,10 +150,7 @@
$: {
if (license) {
setPrice()
setBalance()
setLastPayment()
setNextPayment()
setPrimaryActionText()
setCancelAt()
setTextRows()
setDaysRemainingInMonth()
@ -217,67 +163,71 @@
}
</script>
<Page maxWidth={"100ch"}>
{#if loaded}
<Layout>
<Layout noPadding gap="S">
<Heading>Billing</Heading>
<Body
>Get information about your current usage and manage your plan</Body
>
</Layout>
<Divider />
<DashCard
description="YOUR CURRENT PLAN"
title={planTitle()}
subtitle={planSubtitle()}
primaryActionText={cancelAt ? "Upgrade" : "Manage"}
primaryAction={goToAccountPortal}
{textRows}
>
<Layout gap="S" noPadding>
<Layout gap="S">
<div class="usages">
<Layout noPadding>
{#each staticUsage as usage}
<div class="usage">
<Usage
{usage}
warnWhenFull={warnUsage.includes(usage.name)}
/>
</div>
{/each}
</Layout>
</div>
</Layout>
{#if monthlyUsage.length}
<div class="monthly-container">
<Layout gap="S">
<Heading size="S" weight="light">Monthly</Heading>
<div class="detail">
<Detail size="M">Resets in {daysRemainingInMonth} days</Detail
>
</div>
<div class="usages">
<Layout noPadding>
{#each monthlyUsage as usage}
<div class="usage">
<Usage
{usage}
warnWhenFull={warnUsage.includes(usage.name)}
/>
</div>
{/each}
</Layout>
</div>
</Layout>
</div>
{/if}
</Layout>
</DashCard>
{#if loaded}
<Layout>
<Layout noPadding gap="S">
<Heading>Usage</Heading>
<Body
>Get information about your current usage within Budibase.
{#if accountPortalAccess}
To upgrade your plan and usage limits visit your <Link
on:click={goToAccountPortal}
size="L">Account</Link
>
{:else}
To upgrade your plan and usage limits contact your account holder
{/if}
</Body>
</Layout>
{/if}
</Page>
<Divider />
<DashCard
description="YOUR CURRENT PLAN"
title={planTitle()}
{primaryActionText}
primaryAction={accountPortalAccess ? goToAccountPortal : undefined}
{textRows}
>
<Layout gap="S" noPadding>
<Layout gap="S">
<div class="usages">
<Layout noPadding>
{#each staticUsage as usage}
<div class="usage">
<Usage
{usage}
warnWhenFull={warnUsage.includes(usage.name)}
/>
</div>
{/each}
</Layout>
</div>
</Layout>
{#if monthlyUsage.length}
<div class="monthly-container">
<Layout gap="S">
<Heading size="S" weight="light">Monthly</Heading>
<div class="detail">
<Detail size="M">Resets in {daysRemainingInMonth} days</Detail>
</div>
<div class="usages">
<Layout noPadding>
{#each monthlyUsage as usage}
<div class="usage">
<Usage
{usage}
warnWhenFull={warnUsage.includes(usage.name)}
/>
</div>
{/each}
</Layout>
</div>
</Layout>
</div>
{/if}
</Layout>
</DashCard>
</Layout>
{/if}
<style>
.usages {
@ -289,10 +239,4 @@
margin-bottom: 5px;
margin-top: -8px;
}
/*.monthly-container {*/
/* margin-top: -35px;*/
/*}*/
.card-container {
margin-top: 25px;
}
</style>