feat: new credit flow

This commit is contained in:
Arman
2023-12-01 14:57:27 +01:00
parent 74783974fa
commit a76b5d5b09
6 changed files with 171 additions and 42 deletions
+2 -1
View File
@@ -38,7 +38,8 @@ export const load: LayoutLoad = async ({ depends, url }) => {
];
if (!acceptedRoutes.some((n) => url.pathname.startsWith(n))) {
const redirectUrl = url.pathname ? `redirect=${url.pathname}` : '';
const redirectUrl =
url.pathname && url.pathname !== '/' ? `redirect=${url.pathname}` : '';
const path = url.search ? `${url.search}&${redirectUrl}` : `?${redirectUrl}`;
throw redirect(303, `/login${path}`);
}
@@ -0,0 +1,48 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { Modal } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Button, FormList, InputText } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { organization } from '$lib/stores/organization';
import { sdk } from '$lib/stores/sdk';
export let show = false;
let coupon: string = null;
async function redeem() {
try {
await sdk.forConsole.billing.addCredit($organization.$id, coupon);
addNotification({
type: 'success',
message: `Credit has been added to ${$organization.name}`
});
await invalidate(Dependencies.CREDIT);
await invalidate(Dependencies.ORGANIZATION);
trackEvent(Submit.CreditRedeem, {
coupon
});
coupon = null;
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
trackError(error, Submit.CreditRedeem);
}
}
</script>
<Modal title="Add credits" headerDivider={false} onSubmit={redeem}>
Apply Appwrite credits to your organization.
<FormList>
<InputText placeholder="Promo code" id="code" label="Add promo code" bind:value={coupon} />
</FormList>
<svelte:fragment slot="footer">
<Button text>Cancel</Button>
<Button submit>Add credits</Button>
</svelte:fragment>
</Modal>
@@ -0,0 +1,70 @@
<script lang="ts">
import { Wizard } from '$lib/layout';
import { onDestroy } from 'svelte';
import { addNotification } from '$lib/stores/notifications';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { wizard } from '$lib/stores/wizard';
import { addCreditWizardStore } from './store';
import { createOrgSteps } from '$routes/console/wizard/cloudOrganization/store';
import AddCredit from './wizard/addCredit.svelte';
import { sdk } from '$lib/stores/sdk';
import { organization } from '$lib/stores/organization';
async function onFinish() {
await invalidate(Dependencies.FUNCTIONS);
}
async function create() {
try {
console.log($addCreditWizardStore);
await sdk.forConsole.billing.setOrganizationPaymentMethod(
$organization.$id,
$addCreditWizardStore.paymentId
);
await sdk.forConsole.billing.addCredit($organization.$id, $addCreditWizardStore.coupon);
addNotification({
type: 'success',
message: `Credit has been added to ${$organization.name}`
});
await invalidate(Dependencies.CREDIT);
await invalidate(Dependencies.ORGANIZATION);
trackEvent(Submit.CreditRedeem, {
coupon: $addCreditWizardStore.coupon
});
wizard.hide();
} catch (e) {
addNotification({
type: 'error',
message: e.mesage
});
trackError(e, Submit.CreditRedeem);
}
}
onDestroy(() => {
$addCreditWizardStore = {
coupon: null,
paymentId: null
};
});
$createOrgSteps.set(1, {
label: 'Credits',
component: AddCredit
});
$createOrgSteps.set(2, {
label: 'Payment',
component: AddCredit
});
</script>
<Wizard
title="Add credits"
steps={$createOrgSteps}
finalAction="Add credits"
on:finish={create}
on:exit={onFinish} />
@@ -1,9 +1,5 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { CardGrid, Heading, PaginationInline } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Button, Form, FormList, InputText } from '$lib/elements/forms';
import { CardGrid, Empty, Heading, PaginationInline } from '$lib/components';
import {
Table,
TableBody,
@@ -14,18 +10,20 @@
} from '$lib/elements/table';
import { toLocaleDate } from '$lib/helpers/date';
import type { Credit, CreditList } from '$lib/sdk/billing';
import { addNotification } from '$lib/stores/notifications';
import { organization } from '$lib/stores/organization';
import { sdk } from '$lib/stores/sdk';
import { wizard } from '$lib/stores/wizard';
import { Query } from '@appwrite.io/console';
import { onMount } from 'svelte';
import AddCreditWizard from './addCreditWizard.svelte';
import { Button } from '$lib/elements/forms';
let coupon: string = null;
let offset = 0;
let creditList: CreditList = {
credits: [],
total: 0
};
let show = false;
onMount(async () => {
request();
@@ -33,25 +31,11 @@
const limit = 5;
async function redeem() {
try {
await sdk.forConsole.billing.addCredit($organization.$id, coupon);
addNotification({
type: 'success',
message: `Credit has been added to ${$organization.name}`
});
await invalidate(Dependencies.CREDIT);
await invalidate(Dependencies.ORGANIZATION);
trackEvent(Submit.CreditRedeem, {
coupon
});
coupon = null;
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
trackError(error, Submit.CreditRedeem);
function handleCredits() {
if ($organization?.paymentMethodId || $organization?.backupPaymentMethodId) {
show = true;
} else {
wizard.start(AddCreditWizard);
}
}
@@ -75,20 +59,17 @@
<p class="text">Appwrite credit will automatically be applied to your next invoice.</p>
<svelte:fragment slot="aside">
<h4 class="body-text-1 u-bold">
Credit balance <span class="inline-tag">${balance}</span>
</h4>
<Form onSubmit={redeem} noMargin>
<FormList>
<InputText
placeholder="Coupon code"
id="code"
label="Add credit"
bind:value={coupon}>
<Button secondary submit>Redeem</Button>
</InputText>
</FormList>
</Form>
<div class="u-flex u-cross-center u-main-space-between">
<h4 class="body-text-1 u-bold">
Credit balance <span class="inline-tag">${balance}</span>
</h4>
{#if creditList?.total}
<Button secondary>
<span class="icon-plus" aria-hidden="true"></span>
<span class="text">Add credits</span>
</Button>
{/if}
</div>
{#if creditList?.total}
<Table noStyles noMargin>
<TableHeader>
@@ -116,6 +97,8 @@
<p class="text">Total results: {creditList?.total}</p>
<PaginationInline {limit} bind:offset sum={creditList?.total} hidePages />
</div>
{:else}
<Empty target="credits" on:click={handleCredits}>Add credits</Empty>
{/if}
</svelte:fragment>
</CardGrid>
@@ -1,8 +1,13 @@
import { page } from '$app/stores';
import type { AggregationList } from '$lib/sdk/billing';
import { derived } from 'svelte/store';
import { derived, writable } from 'svelte/store';
export const aggregationList = derived(
page,
($page) => $page.data.aggregationList as AggregationList
);
export const addCreditWizardStore = writable<{ coupon: string; paymentId: string }>({
coupon: null,
paymentId: null
});
@@ -0,0 +1,22 @@
<script lang="ts">
import { Button, FormList, InputText } from '$lib/elements/forms';
import { WizardStep } from '$lib/layout';
import { addCreditWizardStore } from '../store';
</script>
<WizardStep>
<svelte:fragment slot="title">Add credits</svelte:fragment>
<svelte:fragment slot="subtitle">
Add Appwrite credits to your organization. A payment method is required before credits can
be applied.
</svelte:fragment>
<FormList>
<InputText
placeholder="Promo code"
id="code"
label="Add promo code"
bind:value={$addCreditWizardStore.coupon}>
<Button secondary submit>Add</Button>
</InputText>
</FormList>
</WizardStep>