Billing and usage page updates to support different kinds of users and plans
This commit is contained in:
parent
82e8e23dc5
commit
7afcaadc19
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { Body, ProgressBar, Heading, Icon, Link } from "@budibase/bbui"
|
import { Body, ProgressBar, Heading, Icon, Link } from "@budibase/bbui"
|
||||||
import { admin } from "../../stores/portal"
|
import { admin, auth } from "../../stores/portal"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
export let usage
|
export let usage
|
||||||
export let warnWhenFull = false
|
export let warnWhenFull = false
|
||||||
|
@ -9,6 +9,8 @@
|
||||||
let unlimited = false
|
let unlimited = false
|
||||||
let showWarning = false
|
let showWarning = false
|
||||||
|
|
||||||
|
$: accountPortalAccess = $auth?.user?.accountPortalAccess
|
||||||
|
|
||||||
const isUnlimited = () => {
|
const isUnlimited = () => {
|
||||||
if (usage.total === -1) {
|
if (usage.total === -1) {
|
||||||
return true
|
return true
|
||||||
|
@ -66,7 +68,12 @@
|
||||||
{/if}
|
{/if}
|
||||||
{#if showWarning}
|
{#if showWarning}
|
||||||
<Body size="S">
|
<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>
|
</Body>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,12 +3,11 @@
|
||||||
|
|
||||||
export let description = ""
|
export let description = ""
|
||||||
export let title = ""
|
export let title = ""
|
||||||
export let subtitle = ""
|
|
||||||
export let primaryAction
|
export let primaryAction
|
||||||
export let secondaryAction
|
export let secondaryAction
|
||||||
export let primaryActionText
|
export let primaryActionText
|
||||||
export let secondaryActionText
|
export let secondaryActionText
|
||||||
export let primaryCta = false
|
export let primaryCta = true
|
||||||
export let textRows = []
|
export let textRows = []
|
||||||
|
|
||||||
$: primaryDefined = primaryAction && primaryActionText
|
$: primaryDefined = primaryAction && primaryActionText
|
||||||
|
@ -23,14 +22,13 @@
|
||||||
<Detail size="M">{description}</Detail>
|
<Detail size="M">{description}</Detail>
|
||||||
</div>
|
</div>
|
||||||
<Heading size="M">{title}</Heading>
|
<Heading size="M">{title}</Heading>
|
||||||
<div class="dash-card-title">
|
{#if textRows.length}
|
||||||
<Detail size="M">{subtitle}</Detail>
|
<div class="text-rows">
|
||||||
</div>
|
{#each textRows as row}
|
||||||
<div class="text-rows">
|
<Body>{row}</Body>
|
||||||
{#each textRows as row}
|
{/each}
|
||||||
<Body>{row}</Body>
|
</div>
|
||||||
{/each}
|
{/if}
|
||||||
</div>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
Heading,
|
Heading,
|
||||||
Layout,
|
Layout,
|
||||||
notifications,
|
notifications,
|
||||||
Page,
|
|
||||||
Detail,
|
Detail,
|
||||||
|
Link,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { admin, auth, licensing } from "../../../../stores/portal"
|
import { admin, auth, licensing } from "../../../../stores/portal"
|
||||||
|
@ -15,29 +15,20 @@
|
||||||
|
|
||||||
let staticUsage = []
|
let staticUsage = []
|
||||||
let monthlyUsage = []
|
let monthlyUsage = []
|
||||||
let price
|
|
||||||
let lastPayment
|
|
||||||
let cancelAt
|
let cancelAt
|
||||||
let nextPayment
|
|
||||||
let balance
|
|
||||||
let loaded = false
|
let loaded = false
|
||||||
let textRows = []
|
let textRows = []
|
||||||
let daysRemainingInMonth
|
let daysRemainingInMonth
|
||||||
|
let primaryActionText
|
||||||
|
|
||||||
const upgradeUrl = `${$admin.accountPortalUrl}/portal/upgrade`
|
const upgradeUrl = `${$admin.accountPortalUrl}/portal/upgrade`
|
||||||
const manageUrl = `${$admin.accountPortalUrl}/portal/billing`
|
const manageUrl = `${$admin.accountPortalUrl}/portal/billing`
|
||||||
|
|
||||||
const warnUsage = ["Queries", "Automations", "Rows"]
|
const warnUsage = ["Queries", "Automations", "Rows", "Day Passes"]
|
||||||
|
|
||||||
$: quotaUsage = $licensing.quotaUsage
|
$: quotaUsage = $licensing.quotaUsage
|
||||||
$: license = $auth.user?.license
|
$: license = $auth.user?.license
|
||||||
|
$: accountPortalAccess = $auth?.user?.accountPortalAccess
|
||||||
const numberFormatter = new Intl.NumberFormat("en-US", {
|
|
||||||
style: "currency",
|
|
||||||
currency: "USD",
|
|
||||||
minimumFractionDigits: 0,
|
|
||||||
maximumFractionDigits: 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
const setMonthlyUsage = () => {
|
const setMonthlyUsage = () => {
|
||||||
monthlyUsage = []
|
monthlyUsage = []
|
||||||
|
@ -71,49 +62,8 @@
|
||||||
staticUsage = staticUsage.sort((a, b) => a.name.localeCompare(b.name))
|
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 = () => {
|
const setCancelAt = () => {
|
||||||
cancelAt = license?.billing.subscription?.cancelAt
|
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`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const capitalise = string => {
|
const capitalise = string => {
|
||||||
|
@ -126,10 +76,6 @@
|
||||||
return capitalise(license?.plan.type)
|
return capitalise(license?.plan.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
const planSubtitle = () => {
|
|
||||||
return `${license?.plan.price.sessions} day passes`
|
|
||||||
}
|
|
||||||
|
|
||||||
const getDaysRemaining = timestamp => {
|
const getDaysRemaining = timestamp => {
|
||||||
if (!timestamp) {
|
if (!timestamp) {
|
||||||
return
|
return
|
||||||
|
@ -153,16 +99,6 @@
|
||||||
if (cancelAt) {
|
if (cancelAt) {
|
||||||
textRows.push("Subscription has been cancelled")
|
textRows.push("Subscription has been cancelled")
|
||||||
textRows.push(`${getDaysRemaining(cancelAt * 1000)} days remaining`)
|
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 () => {
|
const init = async () => {
|
||||||
try {
|
try {
|
||||||
await licensing.getQuotaUsage()
|
await licensing.getQuotaUsage()
|
||||||
|
@ -201,10 +150,7 @@
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (license) {
|
if (license) {
|
||||||
setPrice()
|
setPrimaryActionText()
|
||||||
setBalance()
|
|
||||||
setLastPayment()
|
|
||||||
setNextPayment()
|
|
||||||
setCancelAt()
|
setCancelAt()
|
||||||
setTextRows()
|
setTextRows()
|
||||||
setDaysRemainingInMonth()
|
setDaysRemainingInMonth()
|
||||||
|
@ -217,67 +163,71 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Page maxWidth={"100ch"}>
|
{#if loaded}
|
||||||
{#if loaded}
|
<Layout>
|
||||||
<Layout>
|
<Layout noPadding gap="S">
|
||||||
<Layout noPadding gap="S">
|
<Heading>Usage</Heading>
|
||||||
<Heading>Billing</Heading>
|
<Body
|
||||||
<Body
|
>Get information about your current usage within Budibase.
|
||||||
>Get information about your current usage and manage your plan</Body
|
{#if accountPortalAccess}
|
||||||
>
|
To upgrade your plan and usage limits visit your <Link
|
||||||
</Layout>
|
on:click={goToAccountPortal}
|
||||||
<Divider />
|
size="L">Account</Link
|
||||||
<DashCard
|
>
|
||||||
description="YOUR CURRENT PLAN"
|
{:else}
|
||||||
title={planTitle()}
|
To upgrade your plan and usage limits contact your account holder
|
||||||
subtitle={planSubtitle()}
|
{/if}
|
||||||
primaryActionText={cancelAt ? "Upgrade" : "Manage"}
|
</Body>
|
||||||
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>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
{/if}
|
<Divider />
|
||||||
</Page>
|
<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>
|
<style>
|
||||||
.usages {
|
.usages {
|
||||||
|
@ -289,10 +239,4 @@
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
margin-top: -8px;
|
margin-top: -8px;
|
||||||
}
|
}
|
||||||
/*.monthly-container {*/
|
|
||||||
/* margin-top: -35px;*/
|
|
||||||
/*}*/
|
|
||||||
.card-container {
|
|
||||||
margin-top: 25px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue