Skip to content

Commit

Permalink
Merge pull request #1552 from ItzNotABug/billing-ui-changes
Browse files Browse the repository at this point in the history
Billing UI changes
  • Loading branch information
ItzNotABug authored Jan 13, 2025
2 parents b35661a + ce24c5b commit 17894b5
Show file tree
Hide file tree
Showing 9 changed files with 519 additions and 409 deletions.
2 changes: 1 addition & 1 deletion src/lib/components/billing/usageRates.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
following rates. Next billing period: {toLocaleDate(nextDate)}.
</p>
{/if}
<Table noStyles>
<Table noStyles noMargin>
<TableHeader>
<TableCellHead>Resource</TableCellHead>
<TableCellHead>Limit</TableCellHead>
Expand Down
7 changes: 5 additions & 2 deletions src/lib/components/collapsibleItem.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
export let noContent = false;
export let isInfo = false;
export let gap = 16;
export let style = null;
export let wrapperStyle = null;
</script>

<li class="collapsible-item" class:is-info={isInfo}>
{#if noContent}
<div class="collapsible-wrapper">
<div class={`collapsible-button u-gap-${gap}`}>
<div class="collapsible-wrapper" style={wrapperStyle}>
<div class={`collapsible-button u-gap-${gap}`} {style}>
<slot />
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import { confirmPayment } from '$lib/stores/stripe';
import { sdk } from '$lib/stores/sdk';
import { toLocaleDate } from '$lib/helpers/date';
import { BillingPlan } from '$lib/constants';
import RetryPaymentModal from './retryPaymentModal.svelte';
import { selectedInvoice, showRetryModal } from './store';
import { Button } from '$lib/elements/forms';
Expand Down Expand Up @@ -130,9 +129,7 @@
<BillingAddress billingAddress={data?.billingAddress} />
<TaxId />
<BudgetCap />
{#if $organization?.billingPlan !== BillingPlan.FREE && !!$organization?.billingBudget}
<BudgetAlert />
{/if}
<BudgetAlert />
<AvailableCredit />
</Container>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@
</script>

<CardGrid hideFooter={$organization?.billingPlan !== BillingPlan.FREE}>
<Heading tag="h2" size="6">Available credit</Heading>
<Heading tag="h2" size="6">
{$organization?.billingPlan === BillingPlan.FREE ? 'Credits' : 'Available credit'}
</Heading>

<p class="text">Appwrite credit will automatically be applied to your next invoice.</p>
<svelte:fragment slot="aside">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { CardGrid, Heading } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Alert, CardGrid, Heading } from '$lib/components';
import { BillingPlan, Dependencies } from '$lib/constants';
import { tierToPlan, upgradeURL } from '$lib/stores/billing';
import { Button, Form, FormList, InputSelectSearch } from '$lib/elements/forms';
import {
Table,
Expand All @@ -15,7 +16,7 @@
} from '$lib/elements/table';
import { symmetricDifference } from '$lib/helpers/array';
import { addNotification } from '$lib/stores/notifications';
import { organization } from '$lib/stores/organization';
import { currentPlan, organization } from '$lib/stores/organization';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
Expand All @@ -39,7 +40,7 @@
if (alerts.some((alert) => alert === selectedAlert)) {
return;
}
if (alerts.length <= 2) {
if (alerts.length <= 3) {
alerts = [...alerts, selectedAlert ? selectedAlert : parseInt(search)];
search = '';
selectedAlert = null;
Expand All @@ -59,7 +60,7 @@
addNotification({
type: 'success',
isHtml: true,
message: `<span>A budget alert has been added to <b>${$organization.name}</b></span>`
message: `<span> ${alerts.length === 0 ? 'Budget alerts removed from' : alerts.length > 1 ? `Budget alerts added to` : 'A budget alert has been added to'} <b>${$organization.name}</b> </span>`
});
trackEvent(Submit.BudgetAlertsUpdate, {
alerts
Expand All @@ -78,65 +79,99 @@

<Form onSubmit={updateBudget}>
<CardGrid>
<Heading tag="h2" size="6">Budget alerts</Heading>
<Heading tag="h2" size="6">Billing alerts</Heading>

<p class="text">
Get notified by email when your organization reaches or exceeds a percent of your
specified budget cap. You can set a maximum of 3 alerts.
{#if !$currentPlan.budgeting}
Get notified by email when your organization meets a percentage of your budget cap. <b
>{tierToPlan($organization.billingPlan).name} organizations will receive one notification
at 75% resource usage.</b>
{:else}
Get notified by email when your organization meets or exceeds a percentage of your
specified billing alert(s).
{/if}
</p>
<svelte:fragment slot="aside">
<FormList>
<div class="u-flex u-gap-16">
<InputSelectSearch
label="Percentage (%) of budget cap"
placeholder="Select a percentage"
id="alerts"
{options}
bind:search
bind:value={selectedAlert}
on:select={() => (search = selectedAlert.toString())} />
<div style="align-self: flex-end">
<Button
secondary
disabled={alerts.length > 2 || (!search && !selectedAlert)}
on:click={addAlert}>
Add alert
</Button>
{#if !$currentPlan.budgeting}
<Alert type="info">
<svelte:fragment slot="title"
>Billing alerts are a Pro plan feature
</svelte:fragment>
Upgrade to a Pro plan to manage when you receive billing alerts for your organization.
</Alert>
{:else}
<FormList>
<Alert type="info">
You can set a maximum of 4 billing alerts per organization.
</Alert>

<div class="u-flex u-gap-16">
<InputSelectSearch
label="Percentage (%) of budget cap"
placeholder="Select a percentage"
id="alerts"
{options}
bind:search
interactiveOutput
bind:value={selectedAlert}
on:select={() => (search = selectedAlert.toString())} />
<div style="align-self: flex-end">
<Button
secondary
disabled={alerts.length > 3 || (!search && !selectedAlert)}
on:click={addAlert}>
Add alert
</Button>
</div>
</div>
</div>
</FormList>
</FormList>

{#if alerts.length}
<Table noMargin noStyles transparent>
<TableHeader>
<TableCellHead>Alert at budget cap %</TableCellHead>
<TableCellHead width={30} />
</TableHeader>
<TableBody>
{#each alerts.sort() as alert}
<TableRow>
<TableCellText title="Percentage">
{alert}%
</TableCellText>
<TableCell>
<Button
text
round
ariaLabel="remove alert"
on:click={() =>
(alerts = alerts.filter((a) => a !== alert))}>
<span class="icon-x" aria-hidden="true" />
</Button>
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
{#if alerts.length}
<Table noMargin noStyles transparent>
<TableHeader>
<TableCellHead>Alert at budget cap %</TableCellHead>
<TableCellHead width={30} />
</TableHeader>
<TableBody>
{#each alerts.sort() as alert}
<TableRow>
<TableCellText title="Percentage">
{alert}%
</TableCellText>
<TableCell>
<Button
text
round
ariaLabel="remove alert"
on:click={() =>
(alerts = alerts.filter((a) => a !== alert))}>
<span class="icon-x" aria-hidden="true" />
</Button>
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
{/if}
{/if}
</svelte:fragment>

<svelte:fragment slot="actions">
<Button disabled={isButtonDisabled} submit>Update</Button>
{#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
<Button
secondary
href={$upgradeURL}
on:click={() => {
trackEvent('click_organization_upgrade', {
from: 'button',
source: 'billing_alerts_card'
});
}}
>Upgrade to Pro
</Button>
{:else}
<Button disabled={isButtonDisabled} submit>Update</Button>
{/if}
</svelte:fragment>
</CardGrid>
</Form>
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,8 @@
<Heading tag="h2" size="6">Budget cap</Heading>

<p class="text">
Restrict your resource usage by setting a budget cap. <button
on:click={() => ($showUsageRatesModal = true)}
type="button"
class="link">Learn more about usage rates.</button>
Restrict your resource usage by setting a budget cap. Cap usage is reset at the
beginning of each billing cycle.
</p>
<svelte:fragment slot="aside">
{#if !$currentPlan.budgeting}
Expand All @@ -76,8 +74,12 @@
<FormList>
<InputSwitch id="cap-active" label="Enable budget cap" bind:value={capActive}>
<svelte:fragment slot="description">
Budget cap limits do not include the base amount of your plan. Cap usage
is reset at the beginning of each billing cycle.
Budget cap limits do not include the base amount of your plan. <button
class="link"
type="button"
on:click={() => ($showUsageRatesModal = true)}
>Learn more about usage rates.
</button>
</svelte:fragment>
</InputSwitch>
{#if capActive}
Expand All @@ -102,7 +104,9 @@
from: 'button',
source: 'billing_budget_cap'
});
}}>Upgrade to Pro</Button>
}}
>Upgrade to Pro
</Button>
{:else}
<Button disabled={$organization?.billingBudget === budget} submit>Update</Button>
{/if}
Expand Down
Loading

0 comments on commit 17894b5

Please sign in to comment.