Skip to content

Commit 17894b5

Browse files
authored
Merge pull request #1552 from ItzNotABug/billing-ui-changes
Billing UI changes
2 parents b35661a + ce24c5b commit 17894b5

File tree

9 files changed

+519
-409
lines changed

9 files changed

+519
-409
lines changed

src/lib/components/billing/usageRates.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
following rates. Next billing period: {toLocaleDate(nextDate)}.
6868
</p>
6969
{/if}
70-
<Table noStyles>
70+
<Table noStyles noMargin>
7171
<TableHeader>
7272
<TableCellHead>Resource</TableCellHead>
7373
<TableCellHead>Limit</TableCellHead>

src/lib/components/collapsibleItem.svelte

+5-2
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
export let noContent = false;
88
export let isInfo = false;
99
export let gap = 16;
10+
11+
export let style = null;
12+
export let wrapperStyle = null;
1013
</script>
1114

1215
<li class="collapsible-item" class:is-info={isInfo}>
1316
{#if noContent}
14-
<div class="collapsible-wrapper">
15-
<div class={`collapsible-button u-gap-${gap}`}>
17+
<div class="collapsible-wrapper" style={wrapperStyle}>
18+
<div class={`collapsible-button u-gap-${gap}`} {style}>
1619
<slot />
1720
</div>
1821
</div>

src/routes/(console)/organization-[organization]/billing/+page.svelte

+1-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import { confirmPayment } from '$lib/stores/stripe';
1818
import { sdk } from '$lib/stores/sdk';
1919
import { toLocaleDate } from '$lib/helpers/date';
20-
import { BillingPlan } from '$lib/constants';
2120
import RetryPaymentModal from './retryPaymentModal.svelte';
2221
import { selectedInvoice, showRetryModal } from './store';
2322
import { Button } from '$lib/elements/forms';
@@ -130,9 +129,7 @@
130129
<BillingAddress billingAddress={data?.billingAddress} />
131130
<TaxId />
132131
<BudgetCap />
133-
{#if $organization?.billingPlan !== BillingPlan.FREE && !!$organization?.billingBudget}
134-
<BudgetAlert />
135-
{/if}
132+
<BudgetAlert />
136133
<AvailableCredit />
137134
</Container>
138135

src/routes/(console)/organization-[organization]/billing/availableCredit.svelte

+3-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@
9090
</script>
9191

9292
<CardGrid hideFooter={$organization?.billingPlan !== BillingPlan.FREE}>
93-
<Heading tag="h2" size="6">Available credit</Heading>
93+
<Heading tag="h2" size="6">
94+
{$organization?.billingPlan === BillingPlan.FREE ? 'Credits' : 'Available credit'}
95+
</Heading>
9496

9597
<p class="text">Appwrite credit will automatically be applied to your next invoice.</p>
9698
<svelte:fragment slot="aside">
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<script lang="ts">
22
import { invalidate } from '$app/navigation';
33
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
4-
import { CardGrid, Heading } from '$lib/components';
5-
import { Dependencies } from '$lib/constants';
4+
import { Alert, CardGrid, Heading } from '$lib/components';
5+
import { BillingPlan, Dependencies } from '$lib/constants';
6+
import { tierToPlan, upgradeURL } from '$lib/stores/billing';
67
import { Button, Form, FormList, InputSelectSearch } from '$lib/elements/forms';
78
import {
89
Table,
@@ -15,7 +16,7 @@
1516
} from '$lib/elements/table';
1617
import { symmetricDifference } from '$lib/helpers/array';
1718
import { addNotification } from '$lib/stores/notifications';
18-
import { organization } from '$lib/stores/organization';
19+
import { currentPlan, organization } from '$lib/stores/organization';
1920
import { sdk } from '$lib/stores/sdk';
2021
import { onMount } from 'svelte';
2122
@@ -39,7 +40,7 @@
3940
if (alerts.some((alert) => alert === selectedAlert)) {
4041
return;
4142
}
42-
if (alerts.length <= 2) {
43+
if (alerts.length <= 3) {
4344
alerts = [...alerts, selectedAlert ? selectedAlert : parseInt(search)];
4445
search = '';
4546
selectedAlert = null;
@@ -59,7 +60,7 @@
5960
addNotification({
6061
type: 'success',
6162
isHtml: true,
62-
message: `<span>A budget alert has been added to <b>${$organization.name}</b></span>`
63+
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>`
6364
});
6465
trackEvent(Submit.BudgetAlertsUpdate, {
6566
alerts
@@ -78,65 +79,99 @@
7879

7980
<Form onSubmit={updateBudget}>
8081
<CardGrid>
81-
<Heading tag="h2" size="6">Budget alerts</Heading>
82+
<Heading tag="h2" size="6">Billing alerts</Heading>
8283

8384
<p class="text">
84-
Get notified by email when your organization reaches or exceeds a percent of your
85-
specified budget cap. You can set a maximum of 3 alerts.
85+
{#if !$currentPlan.budgeting}
86+
Get notified by email when your organization meets a percentage of your budget cap. <b
87+
>{tierToPlan($organization.billingPlan).name} organizations will receive one notification
88+
at 75% resource usage.</b>
89+
{:else}
90+
Get notified by email when your organization meets or exceeds a percentage of your
91+
specified billing alert(s).
92+
{/if}
8693
</p>
8794
<svelte:fragment slot="aside">
88-
<FormList>
89-
<div class="u-flex u-gap-16">
90-
<InputSelectSearch
91-
label="Percentage (%) of budget cap"
92-
placeholder="Select a percentage"
93-
id="alerts"
94-
{options}
95-
bind:search
96-
bind:value={selectedAlert}
97-
on:select={() => (search = selectedAlert.toString())} />
98-
<div style="align-self: flex-end">
99-
<Button
100-
secondary
101-
disabled={alerts.length > 2 || (!search && !selectedAlert)}
102-
on:click={addAlert}>
103-
Add alert
104-
</Button>
95+
{#if !$currentPlan.budgeting}
96+
<Alert type="info">
97+
<svelte:fragment slot="title"
98+
>Billing alerts are a Pro plan feature
99+
</svelte:fragment>
100+
Upgrade to a Pro plan to manage when you receive billing alerts for your organization.
101+
</Alert>
102+
{:else}
103+
<FormList>
104+
<Alert type="info">
105+
You can set a maximum of 4 billing alerts per organization.
106+
</Alert>
107+
108+
<div class="u-flex u-gap-16">
109+
<InputSelectSearch
110+
label="Percentage (%) of budget cap"
111+
placeholder="Select a percentage"
112+
id="alerts"
113+
{options}
114+
bind:search
115+
interactiveOutput
116+
bind:value={selectedAlert}
117+
on:select={() => (search = selectedAlert.toString())} />
118+
<div style="align-self: flex-end">
119+
<Button
120+
secondary
121+
disabled={alerts.length > 3 || (!search && !selectedAlert)}
122+
on:click={addAlert}>
123+
Add alert
124+
</Button>
125+
</div>
105126
</div>
106-
</div>
107-
</FormList>
127+
</FormList>
108128

109-
{#if alerts.length}
110-
<Table noMargin noStyles transparent>
111-
<TableHeader>
112-
<TableCellHead>Alert at budget cap %</TableCellHead>
113-
<TableCellHead width={30} />
114-
</TableHeader>
115-
<TableBody>
116-
{#each alerts.sort() as alert}
117-
<TableRow>
118-
<TableCellText title="Percentage">
119-
{alert}%
120-
</TableCellText>
121-
<TableCell>
122-
<Button
123-
text
124-
round
125-
ariaLabel="remove alert"
126-
on:click={() =>
127-
(alerts = alerts.filter((a) => a !== alert))}>
128-
<span class="icon-x" aria-hidden="true" />
129-
</Button>
130-
</TableCell>
131-
</TableRow>
132-
{/each}
133-
</TableBody>
134-
</Table>
129+
{#if alerts.length}
130+
<Table noMargin noStyles transparent>
131+
<TableHeader>
132+
<TableCellHead>Alert at budget cap %</TableCellHead>
133+
<TableCellHead width={30} />
134+
</TableHeader>
135+
<TableBody>
136+
{#each alerts.sort() as alert}
137+
<TableRow>
138+
<TableCellText title="Percentage">
139+
{alert}%
140+
</TableCellText>
141+
<TableCell>
142+
<Button
143+
text
144+
round
145+
ariaLabel="remove alert"
146+
on:click={() =>
147+
(alerts = alerts.filter((a) => a !== alert))}>
148+
<span class="icon-x" aria-hidden="true" />
149+
</Button>
150+
</TableCell>
151+
</TableRow>
152+
{/each}
153+
</TableBody>
154+
</Table>
155+
{/if}
135156
{/if}
136157
</svelte:fragment>
137158

138159
<svelte:fragment slot="actions">
139-
<Button disabled={isButtonDisabled} submit>Update</Button>
160+
{#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
161+
<Button
162+
secondary
163+
href={$upgradeURL}
164+
on:click={() => {
165+
trackEvent('click_organization_upgrade', {
166+
from: 'button',
167+
source: 'billing_alerts_card'
168+
});
169+
}}
170+
>Upgrade to Pro
171+
</Button>
172+
{:else}
173+
<Button disabled={isButtonDisabled} submit>Update</Button>
174+
{/if}
140175
</svelte:fragment>
141176
</CardGrid>
142177
</Form>

src/routes/(console)/organization-[organization]/billing/budgetCap.svelte

+11-7
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,8 @@
5353
<Heading tag="h2" size="6">Budget cap</Heading>
5454

5555
<p class="text">
56-
Restrict your resource usage by setting a budget cap. <button
57-
on:click={() => ($showUsageRatesModal = true)}
58-
type="button"
59-
class="link">Learn more about usage rates.</button>
56+
Restrict your resource usage by setting a budget cap. Cap usage is reset at the
57+
beginning of each billing cycle.
6058
</p>
6159
<svelte:fragment slot="aside">
6260
{#if !$currentPlan.budgeting}
@@ -76,8 +74,12 @@
7674
<FormList>
7775
<InputSwitch id="cap-active" label="Enable budget cap" bind:value={capActive}>
7876
<svelte:fragment slot="description">
79-
Budget cap limits do not include the base amount of your plan. Cap usage
80-
is reset at the beginning of each billing cycle.
77+
Budget cap limits do not include the base amount of your plan. <button
78+
class="link"
79+
type="button"
80+
on:click={() => ($showUsageRatesModal = true)}
81+
>Learn more about usage rates.
82+
</button>
8183
</svelte:fragment>
8284
</InputSwitch>
8385
{#if capActive}
@@ -102,7 +104,9 @@
102104
from: 'button',
103105
source: 'billing_budget_cap'
104106
});
105-
}}>Upgrade to Pro</Button>
107+
}}
108+
>Upgrade to Pro
109+
</Button>
106110
{:else}
107111
<Button disabled={$organization?.billingBudget === budget} submit>Update</Button>
108112
{/if}

0 commit comments

Comments
 (0)