mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat: new credit flow
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user