mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge pull request #727 from appwrite/fix-missing-events-and-credits
chore: add missing event
This commit is contained in:
@@ -55,7 +55,7 @@
|
||||
<div>
|
||||
<span class="icon-exclamation-circle u-color-text-danger" />
|
||||
<span>
|
||||
{couponData.code} is not a valid promo code
|
||||
{couponData.code.toUpperCase()} is not a valid promo code
|
||||
</span>
|
||||
</div>
|
||||
{:else if couponData?.status === 'active'}
|
||||
@@ -64,11 +64,11 @@
|
||||
<span class="icon-tag u-color-text-success" />
|
||||
<slot data={couponData}>
|
||||
<span>
|
||||
{couponData.code} applied (-${couponData.credits})
|
||||
{couponData.code.toUpperCase()} applied (-${couponData.credits})
|
||||
</span>
|
||||
</slot>
|
||||
</div>
|
||||
<Button text on:click={removeCoupon}>Remove</Button>
|
||||
<Button round text on:click={removeCoupon}><span class="icon-x"></span></Button>
|
||||
</div>
|
||||
{/if}
|
||||
</FormList>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
{#if total}
|
||||
{#each elements as element}
|
||||
{@const value = element[variableName]?.toString()}
|
||||
<div class="box">
|
||||
<div class="box" data-private>
|
||||
<InputRadio
|
||||
id={`${name}-${value}`}
|
||||
{value}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
import { isCloud } from '$lib/system';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import ChangeOrganizationTierCloud from '$routes/console/changeOrganizationTierCloud.svelte';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
export let show = false;
|
||||
|
||||
@@ -43,7 +45,16 @@
|
||||
{/if}
|
||||
</div>
|
||||
{#if $organization?.billingPlan === BillingPlan.STARTER}
|
||||
<Button fullWidth href="https://appwrite.io/pricing" external>
|
||||
<Button
|
||||
fullWidth
|
||||
external
|
||||
on:click={() => {
|
||||
wizard.start(ChangeOrganizationTierCloud);
|
||||
trackEvent('click_organization_upgrade', {
|
||||
from: 'button',
|
||||
source: 'support_menu'
|
||||
});
|
||||
}}>
|
||||
<span class="text">Get Premium support</span>
|
||||
</Button>
|
||||
{:else}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import { getServiceLimit, type PlanServices } from '$lib/stores/billing';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import { isCloud } from '$lib/system';
|
||||
@@ -10,6 +11,7 @@
|
||||
export let service: PlanServices = null;
|
||||
export let name = service;
|
||||
export let total: number = null;
|
||||
export let event: string = null;
|
||||
|
||||
let columns = 0;
|
||||
|
||||
@@ -34,7 +36,14 @@
|
||||
<span class="u-flex u-gap-24 u-main-center u-cross-center">
|
||||
<slot name="limit" {upgradeMethod} {limit}>
|
||||
<span class="text">Upgrade your plan to add {name} to your organization</span>
|
||||
<Button secondary on:click={upgradeMethod}>Upgrade plan</Button>
|
||||
<Button
|
||||
secondary
|
||||
on:click={upgradeMethod}
|
||||
on:click={() =>
|
||||
trackEvent('click_organization_upgrade', {
|
||||
from: 'button',
|
||||
source: event ?? 'table_row_limit_reached'
|
||||
})}>Upgrade plan</Button>
|
||||
</slot>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
import { ContainerButton } from '.';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
export let isFlex = true;
|
||||
export let title: string;
|
||||
@@ -92,8 +93,12 @@
|
||||
<span class="text">
|
||||
You've reached the {services} limit for the {tier} plan. <Button
|
||||
link
|
||||
on:click={upgradeMethod}>Upgrade</Button> your organization for additional
|
||||
resources.
|
||||
on:click={upgradeMethod}
|
||||
on:click={() =>
|
||||
trackEvent('click_organization_upgrade', {
|
||||
from: 'button',
|
||||
source: 'inline_alert'
|
||||
})}>Upgrade</Button> your organization for additional resources.
|
||||
</span>
|
||||
</Alert>
|
||||
{/if}
|
||||
@@ -124,7 +129,12 @@
|
||||
{title.toLocaleLowerCase()} per project on the {tier} plan.
|
||||
{#if $organization?.billingPlan === BillingPlan.STARTER}<Button
|
||||
link
|
||||
on:click={upgradeMethod}>Upgrade</Button>
|
||||
on:click={upgradeMethod}
|
||||
on:click={() =>
|
||||
trackEvent('click_organization_upgrade', {
|
||||
from: 'button',
|
||||
source: 'resource_limit_tag'
|
||||
})}>Upgrade</Button>
|
||||
for addtional {title.toLocaleLowerCase()}.
|
||||
{/if}
|
||||
</p>
|
||||
|
||||
@@ -121,7 +121,13 @@
|
||||
{#if isCloud && $organization?.billingPlan === BillingPlan.STARTER && !$page.url.pathname.startsWith('/console/account')}
|
||||
<Button
|
||||
disabled={$organization?.markedForDeletion}
|
||||
on:click={() => wizard.start(ChangeOrganizationTierCloud)}>
|
||||
on:click={() => {
|
||||
wizard.start(ChangeOrganizationTierCloud);
|
||||
trackEvent('click_organization_upgrade', {
|
||||
from: 'button',
|
||||
source: 'top_nav'
|
||||
});
|
||||
}}>
|
||||
Upgrade
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
class={icon ? `icon-${icon}` : ''}
|
||||
aria-hidden="true" />
|
||||
</div>
|
||||
<div class="alert-sticky-content">
|
||||
<div class="alert-sticky-content" data-private>
|
||||
{#if title}
|
||||
<h4 class="alert-sticky-title">{title}</h4>
|
||||
{/if}
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
org.$id,
|
||||
$changeOrganizationTier.couponCode
|
||||
);
|
||||
trackEvent(Submit.CreditRedeem);
|
||||
}
|
||||
|
||||
//Add budget
|
||||
|
||||
@@ -56,6 +56,12 @@
|
||||
);
|
||||
}
|
||||
|
||||
//Add coupon
|
||||
if ($createOrganization?.couponCode) {
|
||||
await sdk.forConsole.billing.addCredit(org.$id, $createOrganization.couponCode);
|
||||
trackEvent(Submit.CreditRedeem);
|
||||
}
|
||||
|
||||
//Add collaborators
|
||||
if ($createOrganization?.collaborators?.length) {
|
||||
$createOrganization.collaborators.forEach(async (collaborator) => {
|
||||
@@ -110,7 +116,8 @@
|
||||
paymentMethodId: null,
|
||||
collaborators: [],
|
||||
billingAddressId: null,
|
||||
taxId: null
|
||||
taxId: null,
|
||||
couponCode: null
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -71,9 +71,10 @@
|
||||
<p class="text">Appwrite credit will automatically be applied to your next invoice.</p>
|
||||
<svelte:fragment slot="aside">
|
||||
<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>
|
||||
<div class="u-flex u-gap-8 u-cross-center">
|
||||
<h4 class="body-text-1 u-bold">Credit balance</h4>
|
||||
<span class="inline-tag">${balance}</span>
|
||||
</div>
|
||||
{#if creditList?.total}
|
||||
<Button secondary on:click={handleCredits}>
|
||||
<span class="icon-plus" aria-hidden="true"></span>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
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 ChangeOrganizationTierCloud from '$routes/console/changeOrganizationTierCloud.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let capActive = false;
|
||||
@@ -92,7 +94,19 @@
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="actions">
|
||||
<Button disabled={$organization?.billingBudget === budget} submit>Update</Button>
|
||||
{#if $organization?.billingPlan === BillingPlan.STARTER}
|
||||
<Button
|
||||
secondary
|
||||
on:click={() => {
|
||||
wizard.start(ChangeOrganizationTierCloud);
|
||||
trackEvent('click_organization_upgrade', {
|
||||
from: 'button',
|
||||
source: 'billing_budget_cap'
|
||||
});
|
||||
}}>Upgrade to Pro</Button>
|
||||
{:else}
|
||||
<Button disabled={$organization?.billingBudget === budget} submit>Update</Button>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
</Form>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import { abbreviateNumber, formatNumberWithCommas } from '$lib/helpers/numbers';
|
||||
import { humanFileSize } from '$lib/helpers/sizeConvertion';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
let currentInvoice: Invoice;
|
||||
const today = new Date();
|
||||
@@ -136,7 +137,12 @@
|
||||
</Button>
|
||||
<Button
|
||||
disabled={$organization?.markedForDeletion}
|
||||
on:click={() => wizard.start(ChangeOrganizationTierCloud)}>
|
||||
on:click={() => wizard.start(ChangeOrganizationTierCloud)}
|
||||
on:click={() =>
|
||||
trackEvent('click_organization_upgrade', {
|
||||
from: 'button',
|
||||
source: 'billing_tab'
|
||||
})}>
|
||||
Upgrade
|
||||
</Button>
|
||||
</div>
|
||||
@@ -145,7 +151,12 @@
|
||||
<Button
|
||||
text
|
||||
disabled={$organization?.markedForDeletion}
|
||||
on:click={() => wizard.start(ChangeOrganizationTierCloud)}>
|
||||
on:click={() => wizard.start(ChangeOrganizationTierCloud)}
|
||||
on:click={() =>
|
||||
trackEvent('click_organization_plan_update', {
|
||||
from: 'button',
|
||||
source: 'billing_tab'
|
||||
})}>
|
||||
Change plan
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import type { Coupon } from '$lib/sdk/billing';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import { onMount } from 'svelte';
|
||||
import { addCreditWizardStore } from '../store';
|
||||
|
||||
let coupon: string;
|
||||
@@ -18,6 +19,7 @@
|
||||
try {
|
||||
const response = await sdk.forConsole.billing.getCoupon(coupon);
|
||||
couponData = response;
|
||||
$addCreditWizardStore.coupon = coupon;
|
||||
coupon = null;
|
||||
} catch (error) {
|
||||
couponData.code = coupon;
|
||||
@@ -26,6 +28,13 @@
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if ($addCreditWizardStore.coupon) {
|
||||
coupon = $addCreditWizardStore.coupon;
|
||||
validateCoupon();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<WizardStep beforeSubmit={validateCoupon}>
|
||||
@@ -41,6 +50,6 @@
|
||||
$addCreditWizardStore.coupon = e.detail.code;
|
||||
}}
|
||||
let:data>
|
||||
<span>{data.code} has been successfully added</span>
|
||||
<span>{data.code.toUpperCase()} has been successfully added</span>
|
||||
</CouponInput>
|
||||
</WizardStep>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { last } from '$lib/helpers/array';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
export let show = false;
|
||||
const plan = $plansInfo?.get($organization.billingPlan);
|
||||
@@ -89,13 +90,20 @@
|
||||
on:click={() => {
|
||||
show = false;
|
||||
goto(`/console/organization-${$organization.$id}/usage`);
|
||||
}}>View usage</Button>
|
||||
|
||||
}}>
|
||||
View usage
|
||||
</Button>
|
||||
<Button
|
||||
on:click={() => {
|
||||
show = false;
|
||||
wizard.start(ChangeOrganizationTierCloud);
|
||||
}}>Upgrade plan</Button>
|
||||
trackEvent('click_organization_upgrade', {
|
||||
from: 'button',
|
||||
source: 'limit_reached_modal'
|
||||
});
|
||||
}}>
|
||||
Upgrade plan
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
@@ -70,7 +70,10 @@
|
||||
<TableCellHead width={90} />
|
||||
<TableCellHead width={30} />
|
||||
</TableHeader>
|
||||
<TableBody service="members" total={data.organizationMembers.total}>
|
||||
<TableBody
|
||||
service="members"
|
||||
total={data.organizationMembers.total}
|
||||
event="members_list">
|
||||
{#each data.organizationMembers.memberships as member}
|
||||
<TableRow>
|
||||
<TableCell title="Name">
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
import { accumulateFromEndingTotal, total } from '$lib/layout/usage.svelte';
|
||||
import type { OrganizationUsage } from '$lib/sdk/billing';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -42,7 +43,14 @@
|
||||
<Heading tag="h2" size="5">Usage</Heading>
|
||||
|
||||
{#if $organization?.billingPlan === BillingPlan.STARTER}
|
||||
<Button on:click={() => wizard.start(ChangeOrganizationTierCloud)}>
|
||||
<Button
|
||||
on:click={() => {
|
||||
wizard.start(ChangeOrganizationTierCloud);
|
||||
trackEvent('click_organization_upgrade', {
|
||||
from: 'button',
|
||||
source: 'organization_usage'
|
||||
});
|
||||
}}>
|
||||
<span class="text">Upgrade</span>
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { createOrganization } from './store';
|
||||
import type { AddressesList } from '$lib/sdk/billing';
|
||||
import { RadioBoxes } from '$lib/components';
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
let options = [
|
||||
{
|
||||
@@ -33,7 +34,9 @@
|
||||
addressLine2 ? addressLine2 : undefined
|
||||
);
|
||||
$createOrganization.billingAddressId = response.$id;
|
||||
trackEvent(Submit.BillingAddressCreate);
|
||||
} catch (error) {
|
||||
trackError(error, Submit.BillingAddressCreate);
|
||||
throw new Error(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { Box, CreditCardBrandImage } from '$lib/components';
|
||||
import { CouponInput } from '$lib/components/billing';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { toLocaleDate } from '$lib/helpers/date';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import type { Coupon } from '$lib/sdk/billing';
|
||||
import { plansInfo } from '$lib/stores/billing';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { createOrganization, createOrganizationFinalAction } from './store';
|
||||
@@ -15,6 +17,13 @@
|
||||
const today = new Date();
|
||||
const billingPayDate = new Date(today.getTime() + 44 * 24 * 60 * 60 * 1000);
|
||||
|
||||
let coupon: string = null;
|
||||
let couponData: Partial<Coupon> = {
|
||||
code: null,
|
||||
status: null,
|
||||
credits: null
|
||||
};
|
||||
|
||||
async function fetchCard() {
|
||||
try {
|
||||
const card = await sdk.forConsole.billing.getPaymentMethod(
|
||||
@@ -77,6 +86,10 @@
|
||||
{/if}
|
||||
<Box class="u-margin-block-start-32 u-flex u-flex-vertical u-gap-16" radius="small">
|
||||
{#if $createOrganization.billingPlan !== BillingPlan.STARTER}
|
||||
<CouponInput
|
||||
bind:coupon
|
||||
bind:couponData
|
||||
on:validation={(e) => ($createOrganization.couponCode = e.detail.code)} />
|
||||
<span class="u-flex u-main-space-between">
|
||||
<p class="text">{plan.name} plan</p>
|
||||
<p class="text">${plan.price}</p>
|
||||
@@ -85,11 +98,23 @@
|
||||
<p class="text">Additional members ({collaboratorsNumber})</p>
|
||||
<p class="text">${collaboratorPrice * collaboratorsNumber}</p>
|
||||
</span>
|
||||
{#if couponData?.status === 'active'}
|
||||
<span class="u-flex u-main-space-between">
|
||||
<p class="text">Credits applied ({couponData.credits})</p>
|
||||
<p class="text">-${couponData.credits}</p>
|
||||
</span>
|
||||
{/if}
|
||||
<div class="u-sep-block-start" />
|
||||
{/if}
|
||||
<span class="u-flex u-main-space-between">
|
||||
<p class="text">Estimated total</p>
|
||||
<p class="text">${totalExpences}</p>
|
||||
<p class="text">
|
||||
${couponData?.status === 'active'
|
||||
? totalExpences - couponData.credits >= 0
|
||||
? totalExpences - couponData.credits
|
||||
: 0
|
||||
: totalExpences}
|
||||
</p>
|
||||
</span>
|
||||
|
||||
{#if $createOrganization.billingPlan !== BillingPlan.STARTER}
|
||||
|
||||
@@ -15,6 +15,7 @@ export const createOrganization = writable<{
|
||||
collaborators?: string[];
|
||||
billingBudget?: number;
|
||||
taxId?: string;
|
||||
couponCode?: string;
|
||||
}>({
|
||||
id: null,
|
||||
name: null,
|
||||
@@ -22,5 +23,6 @@ export const createOrganization = writable<{
|
||||
paymentMethodId: null,
|
||||
collaborators: [],
|
||||
billingAddressId: null,
|
||||
taxId: null
|
||||
taxId: null,
|
||||
couponCode: null
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import type { AddressesList } from '$lib/sdk/billing';
|
||||
import { RadioBoxes } from '$lib/components';
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
let options = [
|
||||
{
|
||||
@@ -34,7 +35,9 @@
|
||||
addressLine2 ? addressLine2 : undefined
|
||||
);
|
||||
$changeOrganizationTier.billingAddressId = response.$id;
|
||||
trackEvent(Submit.BillingAddressCreate);
|
||||
} catch (error) {
|
||||
trackError(error, Submit.BillingAddressCreate);
|
||||
throw new Error(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,11 +97,11 @@
|
||||
{/if}
|
||||
|
||||
<Box class="u-margin-block-start-32 u-flex u-flex-vertical u-gap-16" radius="small">
|
||||
<CouponInput
|
||||
bind:coupon
|
||||
bind:couponData
|
||||
on:validation={(e) => ($changeOrganizationTier.couponCode = e.detail.code)} />
|
||||
{#if $changeOrganizationTier.billingPlan !== BillingPlan.STARTER}
|
||||
<CouponInput
|
||||
bind:coupon
|
||||
bind:couponData
|
||||
on:validation={(e) => ($changeOrganizationTier.couponCode = e.detail.code)} />
|
||||
<span class="u-flex u-main-space-between">
|
||||
<p class="text">{plan.name} plan</p>
|
||||
<p class="text">${plan.price}</p>
|
||||
|
||||
Reference in New Issue
Block a user