Skip to content

Commit 852261b

Browse files
authored
Merge pull request #694 from appwrite/feat-new-billing-onboarding
feat: new billing onboarding flow
2 parents bf29696 + 203bd6d commit 852261b

File tree

12 files changed

+168
-80
lines changed

12 files changed

+168
-80
lines changed

src/lib/components/billing/paymentBoxes.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { FormList, InputText } from '$lib/elements/forms';
33
import { onDestroy, onMount } from 'svelte';
44
import { CreditCardBrandImage, RadioBoxes } from '..';
5+
import { unmountPaymentElement } from '$lib/stores/stripe';
56
67
export let methods: Record<string, unknown>[];
78
export let group: string;
@@ -33,6 +34,7 @@
3334
3435
onDestroy(() => {
3536
observer.disconnect();
37+
unmountPaymentElement();
3638
});
3739
3840
$: if (element) {

src/lib/elements/forms/button.svelte

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
let classes: string = undefined;
2424
export { classes as class };
2525
export let actions: MultiActionArray = [];
26+
export let submissionLoader = false;
2627
2728
const isSubmitting = hasContext('form')
2829
? getContext<FormContext>('form').isSubmitting
@@ -77,6 +78,12 @@
7778
aria-label={ariaLabel}
7879
type={submit ? 'submit' : 'button'}
7980
use:multiAction={actions}>
80-
<slot />
81+
{#if $isSubmitting && submissionLoader}
82+
<span
83+
class="loader is-small"
84+
style:--p-loader-base-full-color="transparent"
85+
aria-hidden="true" />
86+
{/if}
87+
<slot isSubmitting={$isSubmitting} />
8188
</button>
8289
{/if}

src/lib/layout/wizard.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
} else {
123123
$wizard.step--;
124124
}
125+
wizard.setInterceptor(null);
125126
trackEvent('wizard_back');
126127
}
127128

src/lib/layout/wizardExitModal.svelte

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@
88
99
function handleSubmit() {
1010
dispatch('exit');
11+
show = false;
1112
}
1213
</script>
1314

14-
<Modal title="Exit Process" bind:show onSubmit={handleSubmit} icon="exclamation" state="warning">
15+
<Modal
16+
title="Exit Process"
17+
bind:show
18+
onSubmit={handleSubmit}
19+
icon="exclamation"
20+
state="warning"
21+
headerDivider={false}>
1522
<p>
1623
Are you sure you want to exit from <slot />? All data will be deleted. This action is
1724
irreversible.

src/lib/stores/billing.ts

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { cachedStore } from '$lib/helpers/cache';
88
import { Query, type Models } from '@appwrite.io/console';
99
import { headerAlert } from './headerAlert';
1010
import PaymentAuthRequired from '$lib/components/billing/alerts/paymentAuthRequired.svelte';
11-
import { diffDays, toLocaleDate } from '$lib/helpers/date';
11+
import { diffDays } from '$lib/helpers/date';
1212
import { addNotification, notifications } from './notifications';
1313
import { goto } from '$app/navigation';
1414
import { base } from '$app/paths';
@@ -166,24 +166,6 @@ export function calculateTrialDay(org: Organization) {
166166
return days;
167167
}
168168

169-
export function checkForTrialEnding(org: Organization) {
170-
const days = calculateTrialDay(org);
171-
if (localStorage.getItem('trialEndingNotification') === 'true' || !days) return;
172-
else if (days <= 5) {
173-
addNotification({
174-
type: 'info',
175-
isHtml: true,
176-
message: `<b>We hope you've been enjoying the ${
177-
tierToPlan(org.billingPlan).name
178-
} plan.</b>
179-
You will be billed on a recurring 30-day cycle after your trial period ends on <b>${toLocaleDate(
180-
org.billingStartDate
181-
)}</b>`
182-
});
183-
localStorage.setItem('trialEndingNotification', 'true');
184-
}
185-
}
186-
187169
export async function checkForUsageLimit(org: Organization) {
188170
if (!org?.billingLimits) {
189171
readOnly.set(false);
@@ -295,6 +277,7 @@ export async function checkForFreeOrgOverflow(orgs: Models.TeamList<Record<strin
295277

296278
export async function checkForPostReleaseProModal(orgs: Models.TeamList<Record<string, unknown>>) {
297279
if (!orgs?.teams?.length) return;
280+
if (orgs.total > orgs.teams.length) return; // if the total is greater that the free orgs it means that there are pro orgs
298281
const modalTime = localStorage.getItem('postReleaseProModal');
299282
const now = Date.now();
300283
// show the modal if it was never shown

src/lib/stores/stripe.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,13 @@ export async function initializeStripe() {
3737
paymentElement.mount('#payment-element');
3838
}
3939

40-
// TODO: fix redirect
40+
export async function unmountPaymentElement() {
41+
isStripeInitialized.set(false);
42+
paymentElement?.unmount();
43+
clientSecret = null;
44+
paymentMethod = null;
45+
elements = null;
46+
}
4147

4248
export async function submitStripeCard(name: string, urlRoute?: string) {
4349
try {

src/lib/stores/wizard.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,18 @@ function createWizardStore() {
3131
return {
3232
subscribe,
3333
set,
34-
start: (component: typeof SvelteComponent<unknown>, media: string = null) =>
34+
start: (
35+
component: typeof SvelteComponent<unknown>,
36+
media: string = null,
37+
step: number = 1
38+
) =>
3539
update((n) => {
3640
n.show = true;
3741
n.component = component;
3842
n.interceptor = null;
3943
n.interceptorNotificationEnabled = true;
4044
n.media = media;
41-
n.step = 1;
45+
n.step = step;
4246
n.cover = null;
4347
n.nextDisabled = false;
4448
n.finalAction = null;

src/routes/console/+layout.svelte

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
checkForUsageLimit,
1919
checkPaymentAuthorizationRequired,
2020
calculateTrialDay,
21-
checkForTrialEnding,
2221
paymentExpired,
2322
checkForFreeOrgOverflow,
2423
checkForPostReleaseProModal,
@@ -282,7 +281,6 @@
282281
if (!org) return;
283282
if (isCloud) {
284283
calculateTrialDay(org);
285-
checkForTrialEnding(org);
286284
await paymentExpired(org);
287285
await checkForUsageLimit(org);
288286
checkForMarkedForDeletion(org);

src/routes/console/changeOrganizationTierCloud.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,5 @@
204204
title="Change plan"
205205
steps={$changeTierSteps}
206206
finalAction={$changeOrganizationFinalAction}
207-
on:exit={onFinish} />
207+
on:exit={onFinish}
208+
confirmExit />

src/routes/console/createOrganizationCloud.svelte

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@
2828
2929
async function create() {
3030
try {
31+
// Create free organization if coming from onboarding
32+
if ($page.url.pathname.includes('/console/onboarding')) {
33+
await sdk.forConsole.billing.createOrganization(
34+
ID.unique(),
35+
'Personal Projects',
36+
BillingPlan.STARTER,
37+
null,
38+
null
39+
);
40+
}
41+
3142
const org = await sdk.forConsole.billing.createOrganization(
3243
$createOrganization.id ?? ID.unique(),
3344
$createOrganization.name,
@@ -64,19 +75,21 @@
6475
await sdk.forConsole.billing.updateTaxId(org.$id, $createOrganization.taxId);
6576
}
6677
78+
trackEvent(Submit.OrganizationCreate, {
79+
customId: !!$createOrganization.id,
80+
plan: tierToPlan($createOrganization.billingPlan)?.name,
81+
budget_cap_enabled: !!$createOrganization?.billingBudget,
82+
members_invited: $createOrganization?.collaborators?.length
83+
});
84+
6785
await invalidate(Dependencies.ACCOUNT);
6886
await preloadData(`/console/organization-${org.$id}`);
6987
await goto(`/console/organization-${org.$id}`);
7088
addNotification({
7189
type: 'success',
7290
message: `${$createOrganization.name ?? 'Organization'} has been created`
7391
});
74-
trackEvent(Submit.OrganizationCreate, {
75-
customId: !!$createOrganization.id,
76-
plan: tierToPlan($createOrganization.billingPlan)?.name,
77-
budget_cap_enabled: !!$createOrganization?.billingBudget,
78-
members_invited: $createOrganization?.collaborators?.length
79-
});
92+
8093
wizard.hide();
8194
if (org.billingPlan === BillingPlan.PRO) {
8295
wizard.showCover(HoodieCover);
@@ -129,4 +142,5 @@
129142
title="Create organization"
130143
steps={$createOrgSteps}
131144
finalAction={$createOrganizationFinalAction}
132-
on:exit={onFinish} />
145+
on:exit={onFinish}
146+
confirmExit />

0 commit comments

Comments
 (0)