update: simplify billing context & checks.

This commit is contained in:
Darshan
2025-02-25 19:42:34 +05:30
parent e5ab42659f
commit 41b63982b8
41 changed files with 215 additions and 327 deletions
@@ -1,11 +1,10 @@
<script lang="ts">
import { page } from '$app/stores';
import { BillingPlan } from '$lib/constants';
import { Button } from '$lib/elements/forms';
import { organization } from '$lib/stores/organization';
import { HeaderAlert } from '$lib/layout';
import { isCloud } from '$lib/system';
import { upgradeURL } from '$lib/stores/billing';
import { isFreeTier, upgradeURL } from '$lib/stores/billing';
import { hideNotification } from '$lib/helpers/notifications';
import { backupsBannerId, showPolicyAlert } from '$lib/stores/database';
@@ -16,7 +15,7 @@
</script>
{#if $showPolicyAlert && isCloud && $organization?.$id && $page.url.pathname.match(/\/databases\/database-[^/]+$/)}
{@const isFreePlan = $organization?.billingPlan === BillingPlan.FREE}
{@const isFreePlan = isFreeTier($organization?.billingPlan)}
{@const subtitle = isFreePlan
? 'Upgrade your plan to ensure your data stays safe and backed up'
+3 -2
View File
@@ -4,7 +4,7 @@
import { onMount } from 'svelte';
import { isCloud, isSelfHosted } from '$lib/system';
import { organization } from '$lib/stores/organization';
import { BillingPlan, Dependencies } from '$lib/constants';
import { Dependencies } from '$lib/constants';
import type { BackupArchive, BackupRestoration } from '$lib/sdk/backups';
import { goto, invalidate } from '$app/navigation';
import { page } from '$app/stores';
@@ -12,6 +12,7 @@
import { base } from '$app/paths';
import { getProjectId } from '$lib/helpers/project';
import { toLocaleDate } from '$lib/helpers/date';
import { isFreeTier } from '$lib/stores/billing';
const backupRestoreItems: {
archives: Map<string, BackupArchive>;
@@ -120,7 +121,7 @@
onMount(() => {
// fast path: don't subscribe if org is on a free plan or is self-hosted.
if (isSelfHosted || (isCloud && $organization.billingPlan === BillingPlan.FREE)) return;
if (isSelfHosted || (isCloud && isFreeTier($organization.billingPlan))) return;
return sdk.forConsole.client.subscribe('console', (response) => {
if (!response.channels.includes(`projects.${getProjectId()}`)) return;
@@ -5,11 +5,17 @@
import { BillingPlan } from '$lib/constants';
import { Button } from '$lib/elements/forms';
import { HeaderAlert } from '$lib/layout';
import { hideBillingHeaderRoutes, readOnly, tierToPlan, upgradeURL } from '$lib/stores/billing';
import {
hideBillingHeaderRoutes,
isFreeTier,
readOnly,
tierToPlan,
upgradeURL
} from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
</script>
{#if $organization?.$id && $organization?.billingPlan === BillingPlan.FREE && $readOnly && !hideBillingHeaderRoutes.includes($page.url.pathname)}
{#if $organization?.$id && isFreeTier($organization?.billingPlan) && $readOnly && !hideBillingHeaderRoutes.includes($page.url.pathname)}
<HeaderAlert
type="error"
title={`${$organization.name} usage has reached the ${tierToPlan($organization.billingPlan).name} plan limit`}>
@@ -2,11 +2,12 @@
import { base } from '$app/paths';
import { page } from '$app/stores';
import { trackEvent } from '$lib/actions/analytics';
import { BillingPlan, NEW_DEV_PRO_UPGRADE_COUPON } from '$lib/constants';
import { NEW_DEV_PRO_UPGRADE_COUPON } from '$lib/constants';
import { Button } from '$lib/elements/forms';
import { organization } from '$lib/stores/organization';
import { activeHeaderAlert } from '$routes/(console)/store';
import GradientBanner from '../gradientBanner.svelte';
import { isFreeTier } from '$lib/stores/billing';
let show = true;
@@ -21,7 +22,7 @@
}
</script>
{#if show && $organization?.$id && $organization?.billingPlan === BillingPlan.FREE && !$page.url.pathname.includes('/console/account')}
{#if show && $organization?.$id && isFreeTier($organization?.billingPlan) && !$page.url.pathname.includes('/console/account')}
<GradientBanner on:close={handleClose}>
<div class="u-flex u-gap-24 u-main-center u-cross-center u-flex-vertical-mobile">
<span class="body-text-1">Get $50 Cloud credits for Appwrite Pro.</span>
@@ -1,38 +1,32 @@
<script lang="ts">
import { BillingPlan } from '$lib/constants';
import { formatNum } from '$lib/helpers/string';
import { plansInfo, tierFree, tierPro, tierScale, type Tier } from '$lib/stores/billing';
import { isFreeTier, plansInfo, type Tier } from '$lib/stores/billing';
import { Card, SecondaryTabs, SecondaryTabsItem } from '..';
let selectedTab: Tier = BillingPlan.FREE;
export let downgrade = false;
// get the first available tier as default.
let selectedTab: Tier = $plansInfo.keys().next().value;
$: plan = $plansInfo.get(selectedTab);
</script>
<Card style="--card-padding: 1.5rem">
<div class="comparison-box">
<SecondaryTabs stretch>
<SecondaryTabsItem
disabled={selectedTab === BillingPlan.FREE}
on:click={() => (selectedTab = BillingPlan.FREE)}>
{tierFree.name}
</SecondaryTabsItem>
<SecondaryTabsItem
disabled={selectedTab === BillingPlan.PRO}
on:click={() => (selectedTab = BillingPlan.PRO)}>
{tierPro.name}
</SecondaryTabsItem>
<SecondaryTabsItem
disabled={selectedTab === BillingPlan.SCALE}
on:click={() => (selectedTab = BillingPlan.SCALE)}>
{tierScale.name}
</SecondaryTabsItem>
{#each $plansInfo.entries() as [tier, plan] (tier)}
<SecondaryTabsItem
disabled={selectedTab === tier}
on:click={() => (selectedTab = tier)}>
{plan.name}
</SecondaryTabsItem>
{/each}
</SecondaryTabs>
</div>
<div class="u-margin-block-start-24">
{#if selectedTab === BillingPlan.FREE}
{#if isFreeTier(selectedTab)}
<h3 class="u-bold body-text-1">{plan.name} plan</h3>
{#if downgrade}
<ul class="u-margin-block-start-8 list u-gap-4 u-small">
+32 -90
View File
@@ -1,7 +1,6 @@
<script lang="ts">
import { BillingPlan } from '$lib/constants';
import { formatCurrency } from '$lib/helpers/numbers';
import { plansInfo, tierFree, tierPro, tierScale, type Tier } from '$lib/stores/billing';
import { isFreeTier, plansInfo, type Tier } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { LabelCard } from '..';
@@ -11,97 +10,40 @@
export let selfService = true;
let classes: string = '';
export { classes as class };
$: freePlan = $plansInfo.get(BillingPlan.FREE);
$: proPlan = $plansInfo.get(BillingPlan.PRO);
$: scalePlan = $plansInfo.get(BillingPlan.SCALE);
</script>
{#if billingPlan}
<ul class="u-flex u-flex-vertical u-gap-16 u-margin-block-start-8 {classes}">
<li>
<LabelCard
name="plan"
bind:group={billingPlan}
disabled={anyOrgFree || !selfService}
value={BillingPlan.FREE}
tooltipShow={anyOrgFree}
tooltipText="You are limited to 1 Free organization per account."
padding={1.5}>
<svelte:fragment slot="custom" let:disabled>
<div
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
class:u-opacity-50={disabled}>
<h4 class="body-text-2 u-bold">
{tierFree.name}
{#if $organization?.billingPlan === BillingPlan.FREE && !isNewOrg}
<span class="inline-tag">Current plan</span>
{/if}
</h4>
<p class="u-color-text-offline u-small">
{tierFree.description}
</p>
<p>
{formatCurrency(freePlan?.price ?? 0)}
</p>
</div>
</svelte:fragment>
</LabelCard>
</li>
<li>
<LabelCard
name="plan"
disabled={!selfService}
bind:group={billingPlan}
value={BillingPlan.PRO}
padding={1.5}>
<svelte:fragment slot="custom" let:disabled>
<div
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
class:u-opacity-50={disabled}>
<h4 class="body-text-2 u-bold">
{tierPro.name}
{#if $organization?.billingPlan === BillingPlan.PRO && !isNewOrg}
<span class="inline-tag">Current plan</span>
{/if}
</h4>
<p class="u-color-text-offline u-small">
{tierPro.description}
</p>
<p>
{formatCurrency(proPlan?.price ?? 0)} per member/month + usage
</p>
</div>
</svelte:fragment>
</LabelCard>
</li>
<li>
<LabelCard
name="plan"
bind:group={billingPlan}
value={BillingPlan.SCALE}
padding={1.5}
disabled={!selfService}>
<svelte:fragment slot="custom" let:disabled>
<div
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
class:u-opacity-50={disabled}>
<h4 class="body-text-2 u-bold">
{tierScale.name}
{#if $organization?.billingPlan === BillingPlan.SCALE && !isNewOrg}
<span class="inline-tag">Current plan</span>
{/if}
</h4>
<p class="u-color-text-offline u-small">
{tierScale.description}
</p>
<p>
{formatCurrency(scalePlan?.price ?? 0)} per month + usage
</p>
</div>
</svelte:fragment>
</LabelCard>
</li>
{#each $plansInfo.entries() as [tier, plan] (tier)}
<li>
<LabelCard
name="plan"
bind:group={billingPlan}
disabled={anyOrgFree || !selfService}
value={tier}
tooltipShow={anyOrgFree}
tooltipText="You are limited to 1 Free organization per account."
padding={1.5}>
<svelte:fragment slot="custom" let:disabled>
<div
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
class:u-opacity-50={disabled}>
<h4 class="body-text-2 u-bold">
{plan.name}
{#if isFreeTier($organization?.billingPlan) && !isNewOrg}
<span class="inline-tag">Current plan</span>
{/if}
</h4>
<p class="u-color-text-offline u-small">
{plan.desc}
</p>
<p>
{formatCurrency(plan?.price ?? 0)}
</p>
</div>
</svelte:fragment>
</LabelCard>
</li>
{/each}
</ul>
{/if}
+6 -7
View File
@@ -1,7 +1,6 @@
<script lang="ts">
import { BillingPlan } from '$lib/constants';
import { formatCurrency } from '$lib/helpers/numbers';
import { plansInfo } from '$lib/stores/billing';
import { isFreeTier, plansInfo } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { LabelCard } from '..';
@@ -14,15 +13,15 @@
{#if billingPlan}
<ul class="u-flex u-flex-vertical u-gap-16 u-margin-block-start-8 {classes}">
{#each $plansInfo.values() as plan}
{#each $plansInfo.entries() as [tier, plan]}
<li>
<LabelCard
name="plan"
bind:group={billingPlan}
disabled={(plan.$id === BillingPlan.FREE && anyOrgFree) || !plan.selfService}
value={plan.$id}
tooltipShow={plan.$id === BillingPlan.FREE && anyOrgFree}
tooltipText={plan.$id === BillingPlan.FREE
disabled={(isFreeTier(tier) && anyOrgFree) || !plan.selfService}
value={tier}
tooltipShow={isFreeTier(tier) && anyOrgFree}
tooltipText={isFreeTier(tier)
? 'You are limited to 1 Free organization per account.'
: ''}
padding={1.5}>
+2 -2
View File
@@ -11,7 +11,7 @@
} from '$lib/elements/table';
import { toLocaleDate } from '$lib/helpers/date';
import { organization, type Organization } from '$lib/stores/organization';
import { plansInfo } from '$lib/stores/billing';
import { isFreeTier, plansInfo } from '$lib/stores/billing';
import { abbreviateNumber, formatCurrency } from '$lib/helpers/numbers';
import { BillingPlan } from '$lib/constants';
@@ -49,7 +49,7 @@
}
];
$: isFree = org.billingPlan === BillingPlan.FREE;
$: isFree = isFreeTier(org.billingPlan);
</script>
<Modal bind:show size="big" headerDivider={false} title="Usage rates">
+3 -5
View File
@@ -11,7 +11,7 @@
import { onMount } from 'svelte';
import { organization } from '$lib/stores/organization';
import { BillingPlan } from '$lib/constants';
import { upgradeURL } from '$lib/stores/billing';
import { isFreeTier, upgradeURL } from '$lib/stores/billing';
import { addBottomModalAlerts } from '$routes/(console)/bottomAlerts';
import { project } from '$routes/(console)/project-[project]/store';
import { page } from '$app/stores';
@@ -74,11 +74,9 @@
case 'free':
return false;
case 'pro':
return organizationPlan === BillingPlan.FREE;
return isFreeTier(organizationPlan);
case 'scale':
return (
organizationPlan === BillingPlan.FREE || organizationPlan === BillingPlan.PRO
);
return isFreeTier(organizationPlan) || organizationPlan === BillingPlan.PRO;
}
}
@@ -1,6 +1,4 @@
<script>
import { getNextTier, tierToPlan } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import Card from './card.svelte';
export let source = 'empty_state_card';
@@ -22,7 +20,7 @@
<div class="u-stretch u-flex-vertical u-main-center">
<h3 class="body-text-2 u-bold"><slot name="title" /></h3>
<p class="u-margin-block-start-8">
<slot nextTier={tierToPlan(getNextTier($organization.billingPlan)).name} />
<slot />
</p>
<slot name="cta" {source} />
</div>
+4 -5
View File
@@ -1,19 +1,18 @@
<script>
import Base from './base.svelte';
import { upgradeURL } from '$lib/stores/billing';
import { isFreeTier, upgradeURL } from '$lib/stores/billing';
import { isCloud } from '$lib/system';
import { organization } from '$lib/stores/organization';
import { BillingPlan } from '$lib/constants';
import Button from '$lib/elements/forms/button.svelte';
</script>
<Base>
{#if isCloud}
{#if $organization?.billingPlan !== BillingPlan.FREE}
{#if !isFreeTier($organization?.billingPlan)}
<div class="u-flex-vertical u-gap-8">
<p>
<span class="u-bold">Roles</span>
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<span class="inline-tag u-normal u-x-small">Pro plan</span>
{/if}
</p>
@@ -27,7 +26,7 @@
<div class="u-flex-vertical u-gap-8">
<p>
<span class="u-bold">Roles</span>
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<span class="inline-tag u-normal u-x-small">Pro plan</span>
{/if}
</p>
+2 -3
View File
@@ -18,11 +18,10 @@
import { Container, ContainerHeader } from '$lib/layout';
import { hoursToDays, toLocaleDateTime } from '$lib/helpers/date';
import type { Models } from '@appwrite.io/console';
import { tierToPlan, type PlanServices } from '$lib/stores/billing';
import { tierToPlan, type PlanServices, isFreeTier } from '$lib/stores/billing';
import { isCloud } from '$lib/system';
import { organization } from '$lib/stores/organization';
import { Button } from '$lib/elements/forms';
import { BillingPlan } from '$lib/constants';
export let logs: Models.LogList;
export let offset = 0;
@@ -52,7 +51,7 @@
Logs are retained in rolling {hoursToDays(limit)} intervals with the
{tierToPlan($organization.billingPlan).name}
plan.
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<Button link on:click={upgradeMethod}>Upgrade</Button> to increase your log
retention for a longer period.
{/if}
+6 -8
View File
@@ -1,17 +1,15 @@
<script lang="ts">
import { tooltip } from '$lib/actions/tooltip';
import { BillingPlan } from '$lib/constants';
import { Button } from '$lib/elements/forms';
import { tierToPlan } from '$lib/stores/billing';
import { isFreeTier, tierToPlan } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
export let title: string;
export let tooltipContent =
$organization?.billingPlan === BillingPlan.FREE
? `Upgrade to add more ${title.toLocaleLowerCase()}`
: `You've reached the ${title.toLocaleLowerCase()} limit for the ${
tierToPlan($organization?.billingPlan)?.name
} plan`;
export let tooltipContent = isFreeTier($organization?.billingPlan)
? `Upgrade to add more ${title.toLocaleLowerCase()}`
: `You've reached the ${title.toLocaleLowerCase()} limit for the ${
tierToPlan($organization?.billingPlan)?.name
} plan`;
export let disabled: boolean;
export let buttonText: string;
export let buttonMethod: () => void | Promise<void>;
+6 -5
View File
@@ -11,7 +11,8 @@
showUsageRatesModal,
tierToPlan,
upgradeURL,
type PlanServices
type PlanServices,
isFreeTier
} from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { GRACE_PERIOD_OVERRIDE, isCloud } from '$lib/system';
@@ -64,7 +65,7 @@
$: tier = tierToPlan($organization?.billingPlan)?.name;
$: hasProjectLimitation =
checkForProjectLimitation(serviceId) && $organization?.billingPlan === BillingPlan.FREE;
checkForProjectLimitation(serviceId) && isFreeTier($organization?.billingPlan);
$: hasUsageFees = hasProjectLimitation
? checkForUsageFees($organization?.billingPlan, serviceId)
: false;
@@ -95,7 +96,7 @@
{#if services.length}
<slot name="alert" {limit} {tier} {title} {upgradeMethod} {hasUsageFees} {services}>
{#if $organization?.billingPlan !== BillingPlan.FREE && hasUsageFees}
{#if !isFreeTier($organization?.billingPlan) && hasUsageFees}
<Alert type="info" isStandalone>
<span class="text">
You've reached the {services} limit for the {tier} plan.
@@ -142,7 +143,7 @@
<p class="text">
You are limited to {limit}
{title.toLocaleLowerCase()} per project on the {tier} plan.
{#if $organization?.billingPlan === BillingPlan.FREE}<Button
{#if isFreeTier($organization?.billingPlan)}<Button
link
href={$upgradeURL}
on:click={() =>
@@ -165,7 +166,7 @@
<p class="text">
You are limited to {limit}
{title.toLocaleLowerCase()} per organization on the {tier} plan.
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<Button link href={$upgradeURL}>Upgrade</Button>
for additional {title.toLocaleLowerCase()}.
{/if}
+2 -3
View File
@@ -20,9 +20,8 @@
import { slide } from 'svelte/transition';
import { isCloud } from '$lib/system';
import { Feedback } from '$lib/components/feedback';
import { BillingPlan } from '$lib/constants';
import { logout } from '$lib/helpers/logout';
import { upgradeURL } from '$lib/stores/billing';
import { isFreeTier, upgradeURL } from '$lib/stores/billing';
let showDropdown = false;
let showSupport = false;
@@ -93,7 +92,7 @@
<div class="main-header-end">
<nav class="u-flex is-only-desktop u-cross-center">
{#if isCloud && $organization?.billingPlan === BillingPlan.FREE && !$page.url.pathname.startsWith('/console/account')}
{#if isCloud && isFreeTier($organization?.billingPlan) && !$page.url.pathname.startsWith('/console/account')}
<Button
disabled={$organization?.markedForDeletion}
href={$upgradeURL}
+2 -3
View File
@@ -14,10 +14,9 @@
import { beforeNavigate } from '$app/navigation';
import { Pill } from '$lib/elements';
import { isCloud } from '$lib/system';
import { getServiceLimit, tierToPlan, upgradeURL } from '$lib/stores/billing';
import { getServiceLimit, isFreeTier, tierToPlan, upgradeURL } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { Button } from '$lib/elements/forms';
import { BillingPlan } from '$lib/constants';
import { tooltip } from '$lib/actions/tooltip';
let selectedRequest = 'parameters';
@@ -345,7 +344,7 @@
<Alert>
Logs are retained in rolling {hoursToDays(limit)} intervals
with the {tier} plan.
{#if $organization.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<Button link href={$upgradeURL}>Upgrade</Button> to increase
your log retention for a longer period.
{/if}
+10 -75
View File
@@ -68,45 +68,16 @@ export function getRoleLabel(role: string) {
return roles.find((r) => r.value === role)?.label ?? role;
}
export function tierToPlan(tier: Tier) {
switch (tier) {
case BillingPlan.FREE:
return tierFree;
case BillingPlan.PRO:
return tierPro;
case BillingPlan.SCALE:
return tierScale;
case BillingPlan.GITHUB_EDUCATION:
return tierGitHubEducation;
case BillingPlan.CUSTOM:
return tierCustom;
case BillingPlan.ENTERPRISE:
return tierEnterprise;
default:
return tierFree;
}
export function tierToPlan(tier: Tier): Plan {
return get(plansInfo).get(tier);
}
export function getNextTier(tier: Tier) {
switch (tier) {
case BillingPlan.FREE:
return BillingPlan.PRO;
case BillingPlan.PRO:
return BillingPlan.SCALE;
default:
return BillingPlan.PRO;
}
export function isFreeTier(tier: Tier) {
return get(plansInfo).get(tier).order === 0;
}
export function getPreviousTier(tier: Tier) {
switch (tier) {
case BillingPlan.PRO:
return BillingPlan.FREE;
case BillingPlan.SCALE:
return BillingPlan.PRO;
default:
return BillingPlan.FREE;
}
export function isGithubEducationTier(tier: Tier) {
return get(plansInfo).get(tier).order === 1;
}
export type PlanServices =
@@ -170,42 +141,6 @@ export const failedInvoice = cachedStore<
export const actionRequiredInvoices = writable<InvoiceList>(null);
export type TierData = {
name: string;
description: string;
};
export const tierFree: TierData = {
name: 'Free',
description: 'A great fit for passion projects and small applications.'
};
export const tierGitHubEducation: TierData = {
name: 'GitHub Education',
description: 'For members of GitHub student developers program.'
};
export const tierPro: TierData = {
name: 'Pro',
description:
'For production applications that need powerful functionality and resources to scale.'
};
export const tierScale: TierData = {
name: 'Scale',
description:
'For teams that handle more complex and large projects and need more control and support.'
};
export const tierCustom: TierData = {
name: 'Custom',
description: 'Team on a custom contract'
};
export const tierEnterprise: TierData = {
name: 'Enterprise',
description: 'For enterprises that need more power and premium support.'
};
export const showUsageRatesModal = writable<boolean>(false);
export function checkForUsageFees(plan: Tier, id: PlanServices) {
@@ -249,7 +184,7 @@ export function isServiceLimited(serviceId: PlanServices, plan: Tier, total: num
}
export function calculateTrialDay(org: Organization) {
if (org?.billingPlan === BillingPlan.FREE) return false;
if (isFreeTier(org?.billingPlan)) return false;
const endDate = new Date(org?.billingStartDate);
const today = new Date();
@@ -263,7 +198,7 @@ export function calculateTrialDay(org: Organization) {
}
export async function checkForUsageLimit(org: Organization) {
if (org?.billingPlan !== BillingPlan.FREE) {
if (!isFreeTier(org?.billingPlan)) {
readOnly.set(false);
return;
}
@@ -334,7 +269,7 @@ export async function checkForUsageLimit(org: Organization) {
}
export async function checkPaymentAuthorizationRequired(org: Organization) {
if (org.billingPlan === BillingPlan.FREE) return;
if (isFreeTier(org.billingPlan)) return;
const invoices = await sdk.forConsole.billing.listInvoices(org.$id, [
Query.equal('status', 'requires_authentication')
@@ -450,7 +385,7 @@ export async function checkForMissingPaymentMethod() {
// Display upgrade banner for new users after 1 week for 30 days
export async function checkForNewDevUpgradePro(org: Organization) {
if (org?.billingPlan !== BillingPlan.FREE || !browser) return;
if (!isFreeTier(org?.billingPlan) || !browser) return;
const orgs = await sdk.forConsole.billing.listOrganization([
Query.notEqual('billingPlan', BillingPlan.FREE)
@@ -9,8 +9,8 @@
import { specificationsList } from '$lib/stores/specifications';
import { isCloud } from '$lib/system';
import { organization } from '$lib/stores/organization';
import { BillingPlan } from '$lib/constants';
import SpecificationsTooltip from '../components/specificationsTooltip.svelte';
import { isFreeTier } from '$lib/stores/billing';
let showCustomId = false;
@@ -60,7 +60,7 @@
required
disabled={specificationOptions.length < 1}
options={specificationOptions}
popover={isCloud && $organization?.billingPlan === BillingPlan.FREE
popover={isCloud && isFreeTier($organization?.billingPlan)
? SpecificationsTooltip
: null}
bind:value={$createFunction.specification} />
@@ -5,11 +5,11 @@
import { WizardStep } from '$lib/layout';
import { runtimesList } from '$lib/stores/runtimes';
import { specificationsList } from '$lib/stores/specifications';
import { BillingPlan } from '$lib/constants';
import SpecificationsTooltip from '../components/specificationsTooltip.svelte';
import { template, templateConfig } from '../store';
import { organization } from '$lib/stores/organization';
import { isCloud } from '$lib/system';
import { isFreeTier } from '$lib/stores/billing';
let showCustomId = false;
@@ -103,7 +103,7 @@
required
disabled={specificationOptions.length < 1}
options={specificationOptions}
popover={isCloud && $organization?.billingPlan === BillingPlan.FREE
popover={isCloud && isFreeTier($organization?.billingPlan)
? SpecificationsTooltip
: null}
bind:value={$templateConfig.specification} />
+3 -2
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { page } from '$app/stores';
import { BillingPlan, INTERVAL } from '$lib/constants';
import { INTERVAL } from '$lib/constants';
import { Logs } from '$lib/layout';
import Footer from '$lib/layout/footer.svelte';
import Header from '$lib/layout/header.svelte';
@@ -23,6 +23,7 @@
checkForNewDevUpgradePro,
checkForUsageLimit,
checkPaymentAuthorizationRequired,
isFreeTier,
paymentExpired,
plansInfo,
showUsageRatesModal
@@ -284,7 +285,7 @@
checkForMarkedForDeletion(org);
await checkForNewDevUpgradePro(org);
if (org?.billingPlan !== BillingPlan.FREE) {
if (!isFreeTier(org?.billingPlan)) {
await paymentExpired(org);
await checkPaymentAuthorizationRequired(org);
await checkForMandate(org);
@@ -17,10 +17,15 @@
import { Pill } from '$lib/elements';
import type { Models } from '@appwrite.io/console';
import type { Organization } from '$lib/stores/organization';
import { daysLeftInTrial, plansInfo, tierToPlan } from '$lib/stores/billing';
import {
daysLeftInTrial,
isFreeTier,
isGithubEducationTier,
plansInfo,
tierToPlan
} from '$lib/stores/billing';
import { tooltip } from '$lib/actions/tooltip';
import { toLocaleDate } from '$lib/helpers/date';
import { BillingPlan } from '$lib/constants';
import { goto } from '$app/navigation';
export let data: PageData;
@@ -71,7 +76,7 @@
</svelte:fragment>
<svelte:fragment slot="status">
{#if isCloudOrg(organization)}
{#if organization?.billingPlan === BillingPlan.FREE || organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
{#if isFreeTier(organization?.billingPlan) || isGithubEducationTier(organization?.billingPlan)}
<div
class="u-flex u-cross-center"
use:tooltip={{
@@ -82,7 +87,7 @@
>{tierToPlan(organization?.billingPlan)?.name}</Pill>
</div>
{/if}
{#if organization?.billingTrialStartDate && $daysLeftInTrial > 0 && organization.billingPlan !== BillingPlan.FREE && $plansInfo.get(organization.billingPlan)?.trialDays}
{#if organization?.billingTrialStartDate && $daysLeftInTrial > 0 && !isFreeTier(organization.billingPlan) && $plansInfo.get(organization.billingPlan)?.trialDays}
<div
class="u-flex u-cross-center"
use:tooltip={{
@@ -14,7 +14,7 @@
} from '$lib/layout';
import { type PaymentList } from '$lib/sdk/billing';
import { app } from '$lib/stores/app';
import { isOrganization } from '$lib/stores/billing.js';
import { isFreeTier, isGithubEducationTier, isOrganization } from '$lib/stores/billing.js';
import { addNotification } from '$lib/stores/notifications';
import {
organizationList,
@@ -236,7 +236,7 @@
placeholder="Select organization"
id="organization" />
{/if}
{#if selectedOrgId && (selectedOrg?.billingPlan === BillingPlan.FREE || !selectedOrg?.paymentMethodId)}
{#if selectedOrgId && (isFreeTier(selectedOrg?.billingPlan) || !selectedOrg?.paymentMethodId)}
{#if selectedOrgId === newOrgId}
<InputText
label="Organization name"
@@ -295,7 +295,7 @@
</div>
</div>
{/if}
{#if selectedOrg?.$id && selectedOrg?.billingPlan !== BillingPlan.FREE && selectedOrg?.billingPlan !== BillingPlan.GITHUB_EDUCATION}
{#if selectedOrg?.$id && !isFreeTier(selectedOrg?.billingPlan) && !isGithubEducationTier(selectedOrg?.billingPlan)}
<section
class="card u-margin-block-start-24"
style:--p-card-padding="1.5rem"
@@ -15,7 +15,7 @@
WizardSecondaryFooter
} from '$lib/layout';
import type { Coupon, PaymentList } from '$lib/sdk/billing';
import { isOrganization, tierToPlan } from '$lib/stores/billing';
import { isFreeTier, isOrganization, tierToPlan } from '$lib/stores/billing';
import { addNotification } from '$lib/stores/notifications';
import {
organizationList,
@@ -28,8 +28,8 @@
import { onMount } from 'svelte';
import { writable } from 'svelte/store';
$: anyOrgFree = $organizationList.teams?.some(
(org) => (org as Organization)?.billingPlan === BillingPlan.FREE
$: anyOrgFree = $organizationList.teams?.some((org) =>
isFreeTier((org as Organization)?.billingPlan)
);
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$/i;
let previousPage: string = base;
@@ -126,7 +126,7 @@
try {
let org: Organization | OrganizationError;
if (billingPlan === BillingPlan.FREE) {
if (isFreeTier(billingPlan)) {
org = await sdk.forConsole.billing.createOrganization(
ID.unique(),
name,
@@ -192,7 +192,7 @@
}
}
$: if (billingPlan !== BillingPlan.FREE) {
$: if (!isFreeTier(billingPlan)) {
loadPaymentMethods();
}
</script>
@@ -219,7 +219,7 @@
<Button href="https://appwrite.io/pricing" external link>pricing page</Button>.
</p>
<SelectPlan bind:billingPlan {anyOrgFree} isNewOrg />
{#if billingPlan !== BillingPlan.FREE}
{#if !isFreeTier(billingPlan)}
<FormList class="u-margin-block-start-24">
<InputTags
bind:tags={collaborators}
@@ -244,7 +244,7 @@
{/if}
</Form>
<svelte:fragment slot="aside">
{#if billingPlan !== BillingPlan.FREE}
{#if !isFreeTier(billingPlan)}
<EstimatedTotal bind:billingBudget {billingPlan} {collaborators} bind:couponData />
{:else}
<PlanComparisonBox />
+8 -2
View File
@@ -12,7 +12,13 @@
import { isCloud } from '$lib/system';
import { ID } from '@appwrite.io/console';
import { onMount } from 'svelte';
import { tierToPlan, type Tier, plansInfo, isOrganization } from '$lib/stores/billing';
import {
tierToPlan,
type Tier,
plansInfo,
isOrganization,
isFreeTier
} from '$lib/stores/billing';
import { formatCurrency } from '$lib/helpers/numbers';
import { base } from '$app/paths';
import { checkPricingRefAndRedirect } from '$lib/helpers/pricingRedirect';
@@ -46,7 +52,7 @@
async function handleSubmit() {
const orgName = name?.length ? name : 'Personal Projects';
if (isCloud) {
if (plan === BillingPlan.FREE) {
if (isFreeTier(plan)) {
try {
const org = await sdk.forConsole.billing.createOrganization(
ID.unique(),
@@ -19,9 +19,8 @@
import { Button } from '$lib/elements/forms';
import AddCreditModal from './addCreditModal.svelte';
import { formatCurrency } from '$lib/helpers/numbers';
import { BillingPlan } from '$lib/constants';
import { trackEvent } from '$lib/actions/analytics';
import { upgradeURL } from '$lib/stores/billing';
import { isFreeTier, upgradeURL } from '$lib/stores/billing';
import { Pill } from '$lib/elements';
import { tooltip } from '$lib/actions/tooltip';
@@ -89,14 +88,14 @@
}
</script>
<CardGrid hideFooter={$organization?.billingPlan !== BillingPlan.FREE}>
<CardGrid hideFooter={!isFreeTier($organization?.billingPlan)}>
<Heading tag="h2" size="6">
{$organization?.billingPlan === BillingPlan.FREE ? 'Credits' : 'Available credit'}
{isFreeTier($organization?.billingPlan) ? 'Credits' : 'Available credit'}
</Heading>
<p class="text">Appwrite credit will automatically be applied to your next invoice.</p>
<svelte:fragment slot="aside">
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<Alert type="info">
<svelte:fragment slot="title">Upgrade to Pro to add credits</svelte:fragment>
Upgrade to a Pro plan to add credits to your organization. For more information on what
@@ -173,7 +172,7 @@
{/if}
</svelte:fragment>
<svelte:fragment slot="actions">
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<Button
secondary
href={$upgradeURL}
@@ -2,8 +2,8 @@
import { invalidate } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { Alert, CardGrid, Heading } from '$lib/components';
import { BillingPlan, Dependencies } from '$lib/constants';
import { tierToPlan, upgradeURL } from '$lib/stores/billing';
import { Dependencies } from '$lib/constants';
import { isFreeTier, isGithubEducationTier, tierToPlan, upgradeURL } from '$lib/stores/billing';
import { Button, Form, FormList, InputSelectSearch } from '$lib/elements/forms';
import {
Table,
@@ -163,7 +163,7 @@
</svelte:fragment>
<svelte:fragment slot="actions">
{#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
{#if isFreeTier($organization?.billingPlan) || isGithubEducationTier($organization?.billingPlan)}
<Button
secondary
href={$upgradeURL}
@@ -2,9 +2,9 @@
import { invalidate } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { Alert, CardGrid, Heading } from '$lib/components';
import { BillingPlan, Dependencies } from '$lib/constants';
import { Dependencies } from '$lib/constants';
import { Button, Form, FormList, InputNumber, InputSwitch } from '$lib/elements/forms';
import { showUsageRatesModal, upgradeURL } from '$lib/stores/billing';
import { isFreeTier, showUsageRatesModal, upgradeURL } from '$lib/stores/billing';
import { addNotification } from '$lib/stores/notifications';
import { organization, currentPlan } from '$lib/stores/organization';
import { sdk } from '$lib/stores/sdk';
@@ -96,7 +96,7 @@
</svelte:fragment>
<svelte:fragment slot="actions">
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<Button
secondary
href={$upgradeURL}
@@ -6,7 +6,8 @@
import { sdk } from '$lib/stores/sdk';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { organization } from '$lib/stores/organization';
import { BillingPlan, Dependencies } from '$lib/constants';
import { Dependencies } from '$lib/constants';
import { isFreeTier } from '$lib/stores/billing.js';
export let showDelete = false;
export let isBackup = false;
@@ -16,7 +17,7 @@
let error: string;
async function removeDefaultMethod() {
if ($organization?.billingPlan !== BillingPlan.FREE && !hasOtherMethod) return;
if (!isFreeTier($organization?.billingPlan) && !hasOtherMethod) return;
try {
await sdk.forConsole.billing.removeOrganizationPaymentMethod($organization.$id);
@@ -35,7 +36,7 @@
}
}
async function removeBackuptMethod() {
if ($organization?.billingPlan !== BillingPlan.FREE && !hasOtherMethod) return;
if (!isFreeTier($organization?.billingPlan) && !hasOtherMethod) return;
showDelete = false;
try {
@@ -10,12 +10,12 @@
DropListItem,
Heading
} from '$lib/components';
import { BillingPlan, Dependencies } from '$lib/constants';
import { Dependencies } from '$lib/constants';
import { addNotification } from '$lib/stores/notifications';
import { organization } from '$lib/stores/organization';
import { Button } from '$lib/elements/forms';
import { hasStripePublicKey, isCloud } from '$lib/system';
import { paymentMethods } from '$lib/stores/billing';
import { isFreeTier, isGithubEducationTier, paymentMethods } from '$lib/stores/billing';
import type { PaymentMethodData } from '$lib/sdk/billing';
import DeleteOrgPayment from './deleteOrgPayment.svelte';
import ReplaceCard from './replaceCard.svelte';
@@ -195,7 +195,7 @@
</article>
{/if}
</div>
{#if $organization?.billingPlan !== BillingPlan.FREE && $organization?.billingPlan !== BillingPlan.GITHUB_EDUCATION}
{#if !isFreeTier($organization?.billingPlan) && !isGithubEducationTier($organization?.billingPlan)}
<div class="u-flex u-flex-vertical u-gap-8">
{#if $organization?.backupPaymentMethodId}
<h4 class="u-bold body-text-2">Backup</h4>
@@ -330,5 +330,5 @@
bind:showDelete
{hasOtherMethod}
isBackup={isSelectedBackup}
disabled={$organization?.billingPlan !== BillingPlan.FREE && !hasOtherMethod} />
disabled={!isFreeTier($organization?.billingPlan) && !hasOtherMethod} />
{/if}
@@ -3,7 +3,7 @@
import { Card, CardGrid, Collapsible, CollapsibleItem, Heading } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { toLocaleDate } from '$lib/helpers/date';
import { plansInfo, upgradeURL } from '$lib/stores/billing';
import { isFreeTier, isGithubEducationTier, plansInfo, upgradeURL } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import type { Aggregation, CreditList, Invoice, Plan } from '$lib/sdk/billing';
import { abbreviateNumber, formatCurrency, formatNumberWithCommas } from '$lib/helpers/numbers';
@@ -46,8 +46,7 @@
<div class="u-flex">
<span class="body-text-2">{currentPlan.name} plan</span>
<div class="body-text-2 u-margin-inline-start-auto">
{isTrial ||
$organization?.billingPlan === BillingPlan.GITHUB_EDUCATION
{isTrial || isGithubEducationTier($organization?.billingPlan)
? formatCurrency(0)
: currentPlan
? formatCurrency(currentPlan?.price)
@@ -173,7 +172,7 @@
</CollapsibleItem>
{/if}
{#if $organization?.billingPlan !== BillingPlan.FREE && $organization?.billingPlan !== BillingPlan.GITHUB_EDUCATION}
{#if !isFreeTier($organization?.billingPlan) && !isGithubEducationTier($organization?.billingPlan)}
<CollapsibleItem
noContent
gap={4}
@@ -208,7 +207,7 @@
</Card>
</svelte:fragment>
<svelte:fragment slot="actions">
{#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
{#if isFreeTier($organization?.billingPlan) || isGithubEducationTier($organization?.billingPlan)}
<div
class="u-flex u-flex-vertical-mobile u-cross-center u-gap-16 u-flex-wrap u-width-full-line u-main-end">
<Button text href={`${base}/organization-${$organization?.$id}/usage`}>
@@ -28,7 +28,13 @@
WizardSecondaryFooter
} from '$lib/layout';
import { type Coupon, type PaymentList } from '$lib/sdk/billing';
import { isOrganization, plansInfo, tierToPlan, type Tier } from '$lib/stores/billing';
import {
isOrganization,
plansInfo,
tierToPlan,
type Tier,
isFreeTier
} from '$lib/stores/billing';
import { addNotification } from '$lib/stores/notifications';
import {
currentPlan,
@@ -45,8 +51,8 @@
export let data;
$: anyOrgFree = $organizationList.teams?.find(
(org) => (org as Organization)?.billingPlan === BillingPlan.FREE
$: anyOrgFree = $organizationList.teams?.find((org) =>
isFreeTier((org as Organization)?.billingPlan)
);
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$/i;
let previousPage: string = base;
@@ -276,7 +282,7 @@
$: isUpgrade = $plansInfo.get(billingPlan).order > $currentPlan.order;
$: isDowngrade = $plansInfo.get(billingPlan).order < $currentPlan.order;
$: if (billingPlan !== BillingPlan.FREE) {
$: if (isFreeTier(billingPlan)) {
loadPaymentMethods();
}
$: isButtonDisabled = ($currentPlan?.$id as Tier) === billingPlan;
@@ -303,7 +309,7 @@
<SelectPlan bind:billingPlan anyOrgFree={!!anyOrgFree} class="u-margin-block-16" />
{#if isDowngrade}
{#if billingPlan === BillingPlan.FREE}
{#if isFreeTier(billingPlan)}
<PlanExcess
tier={BillingPlan.FREE}
class="u-margin-block-start-24"
@@ -328,7 +334,7 @@
{/if}
{/if}
<!-- Show email input if upgrading from free plan -->
{#if billingPlan !== BillingPlan.FREE && $organization.billingPlan !== billingPlan && $organization.billingPlan !== BillingPlan.CUSTOM && isUpgrade}
{#if $organization.billingPlan !== billingPlan && tierToPlan(billingPlan)?.addons.seats?.supported && isUpgrade}
<FormList class="u-margin-block-start-16">
<InputTags
bind:tags={collaborators}
@@ -350,7 +356,8 @@
</Button>
{/if}
{/if}
{#if isDowngrade && billingPlan === BillingPlan.FREE}
<!-- TODO: how do we check against the free plan -->
{#if isDowngrade && isFreeTier(billingPlan)}
<FormList class="u-margin-block-start-24">
<InputSelect
id="reason"
@@ -369,13 +376,16 @@
{/if}
</Form>
<svelte:fragment slot="aside">
{#if billingPlan !== BillingPlan.FREE && $organization.billingPlan !== billingPlan && $organization.billingPlan !== BillingPlan.CUSTOM && isUpgrade}
<!-- TODO: we need a way to check for custom plans -->
{#if $organization.billingPlan !== billingPlan && $organization.billingPlan !== BillingPlan.CUSTOM && isUpgrade}
<EstimatedTotal
bind:billingBudget
bind:couponData
organizationId={$organization.$id}
{billingPlan}
{collaborators} />
<!-- TODO: we need a way to check for custom plans -->
{:else if $organization.billingPlan !== BillingPlan.CUSTOM}
<PlanComparisonBox downgrade={isDowngrade} />
{/if}
@@ -12,7 +12,6 @@
Tab,
Tabs
} from '$lib/components';
import { BillingPlan } from '$lib/constants';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import { toLocaleDate } from '$lib/helpers/date';
@@ -21,6 +20,8 @@
import {
daysLeftInTrial,
getServiceLimit,
isFreeTier,
isGithubEducationTier,
plansInfo,
readOnly,
tierToPlan
@@ -110,15 +111,15 @@
<span class="u-trim">
{$organization.name}
</span>
{#if isCloud && $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
{#if isCloud && isGithubEducationTier($organization?.billingPlan)}
<Pill class="eyebrow-heading-3" style="--p-tag-content-height:2rem">
<span class="icon-github" aria-hidden="true" />EDUCATION
</Pill>
{:else if isCloud && $organization?.billingPlan === BillingPlan.FREE}
{:else if isCloud && isFreeTier($organization?.billingPlan)}
<Pill class="eyebrow-heading-3" style="--p-tag-content-height:2rem"
>FREE</Pill>
{/if}
{#if isCloud && $organization?.billingTrialStartDate && $daysLeftInTrial > 0 && $organization.billingPlan !== BillingPlan.FREE && $plansInfo.get($organization.billingPlan)?.trialDays}
{#if isCloud && $organization?.billingTrialStartDate && $daysLeftInTrial > 0 && !isFreeTier($organization.billingPlan) && $plansInfo.get($organization.billingPlan)?.trialDays}
<div
class="u-flex u-cross-center"
use:tooltip={{
@@ -162,12 +163,11 @@
</a>
<div
use:tooltip={{
content:
$organization?.billingPlan === BillingPlan.FREE
? `Upgrade to add more members`
: `You've reached the members limit for the ${
tierToPlan($organization?.billingPlan)?.name
} plan`,
content: isFreeTier($organization?.billingPlan)
? `Upgrade to add more members`
: `You've reached the members limit for the ${
tierToPlan($organization?.billingPlan)?.name
} plan`,
disabled: !areMembersLimited
}}>
{#if $isOwner}
@@ -3,6 +3,7 @@
import { Card, CardGrid, Heading, ProgressBarBig } from '$lib/components';
import {
getServiceLimit,
isFreeTier,
showUsageRatesModal,
type Tier,
upgradeURL
@@ -40,7 +41,7 @@
<div class="u-flex u-cross-center u-main-space-between">
<Heading tag="h2" size="5">Usage</Heading>
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<Button
href={$upgradeURL}
on:click={() => {
@@ -70,7 +71,7 @@
class="link"
type="button">Learn more about plan usage limits.</button>
</p>
{:else if $organization.billingPlan === BillingPlan.FREE}
{:else if isFreeTier($organization.billingPlan)}
<p class="text">
If you exceed the limits of the Free plan, services for your organization's projects
may be disrupted.
@@ -15,7 +15,7 @@
} from '$lib/elements/table';
import { toLocaleDate } from '$lib/helpers/date';
import { formatCurrency } from '$lib/helpers/numbers';
import { plansInfo, tierToPlan } from '$lib/stores/billing';
import { isFreeTier, plansInfo, tierToPlan } from '$lib/stores/billing';
import { newMemberModal, organization } from '$lib/stores/organization';
import type { Models } from '@appwrite.io/console';
@@ -30,7 +30,7 @@
<p class="text">The number of members in your organization.</p>
<svelte:fragment slot="aside">
{#if $organization.billingPlan !== BillingPlan.FREE}
{#if !isFreeTier($organization.billingPlan)}
<div class="u-flex u-flex-vertical">
<div class="u-flex u-main-space-between">
<p>
@@ -15,7 +15,7 @@
<p class="text">Enable or disable Appwrite branding in your email template signature.</p>
<svelte:fragment slot="aside">
<EmptyCardImageCloud source="email_signature_card" let:nextTier noAspectRatio>
<EmptyCardImageCloud source="email_signature_card" noAspectRatio>
<svelte:fragment slot="image">
<div class=" is-only-mobile u-width-full-line u-height-100-percent">
{#if $app.themeInUse === 'dark'}
@@ -51,7 +51,8 @@
</div>
</svelte:fragment>
<svelte:fragment slot="title">Upgrade to edit email signature</svelte:fragment>
Upgrade to a {nextTier} plan to enable or disable Appwrite branding in your emails.
<!-- Confirm copy of paid plan -->
Upgrade to a paid plan to enable or disable Appwrite branding in your emails.
<svelte:fragment let:source slot="cta">
<Button
@@ -8,9 +8,8 @@
import { ID } from '@appwrite.io/console';
import { createEventDispatcher } from 'svelte';
import { isCloud } from '$lib/system';
import { BillingPlan } from '$lib/constants';
import { organization } from '$lib/stores/organization';
import { upgradeURL } from '$lib/stores/billing';
import { isFreeTier, upgradeURL } from '$lib/stores/billing';
import CreatePolicy from './database-[database]/backups/createPolicy.svelte';
import { cronExpression, type UserBackupPolicy } from '$lib/helpers/backups';
@@ -126,7 +125,7 @@
{#if isCloud}
<div class="u-flex-vertical u-gap-24 u-padding-block-start-24">
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
{#if showPlanUpgradeAlert}
<Alert
type="warning"
@@ -1,7 +1,7 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { Alert, EmptySearch, PaginationWithLimit, ViewSelector } from '$lib/components';
import { BillingPlan, Dependencies } from '$lib/constants';
import { Dependencies } from '$lib/constants';
import { Button } from '$lib/elements/forms';
import { hoursToDays } from '$lib/helpers/date';
import { Container, ContainerHeader } from '$lib/layout';
@@ -9,7 +9,7 @@
import { onMount } from 'svelte';
import { func } from '../store';
import { organization } from '$lib/stores/organization';
import { getServiceLimit, showUsageRatesModal } from '$lib/stores/billing';
import { getServiceLimit, isFreeTier, showUsageRatesModal } from '$lib/stores/billing';
import { project } from '$routes/(console)/project-[project]/store';
import Create from '../create.svelte';
import { abbreviateNumber } from '$lib/helpers/numbers';
@@ -171,7 +171,7 @@
{hoursToDays(logs)} of logs
</li>
</ul>
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<p class="text">
<button class="link" type="button" on:click|preventDefault={upgradeMethod}
>Upgrade</button>
@@ -3,7 +3,7 @@
import { page } from '$app/stores';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { CardGrid, Heading } from '$lib/components';
import { BillingPlan, Dependencies } from '$lib/constants';
import { Dependencies } from '$lib/constants';
import { Button, Form, FormList } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
@@ -17,6 +17,7 @@
import { isCloud } from '$lib/system';
import { organization } from '$lib/stores/organization';
import SpecificationsTooltip from '$lib/wizards/functions/components/specificationsTooltip.svelte';
import { isFreeTier } from '$lib/stores/billing';
const functionId = $page.params.function;
let runtime: string = null;
@@ -108,7 +109,7 @@
placeholder="Select runtime specification"
bind:value={specification}
options={specificationOptions}
popover={isCloud && $organization?.billingPlan === BillingPlan.FREE
popover={isCloud && isFreeTier($organization?.billingPlan)
? SpecificationsTooltip
: null}
required
@@ -13,7 +13,7 @@
import InputPassword from '$lib/elements/forms/inputPassword.svelte';
import { sdk } from '$lib/stores/sdk';
import { invalidate } from '$app/navigation';
import { BillingPlan, Dependencies } from '$lib/constants';
import { Dependencies } from '$lib/constants';
import { addNotification } from '$lib/stores/notifications';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import InputNumber from '$lib/elements/forms/inputNumber.svelte';
@@ -23,7 +23,7 @@
import { organization } from '$lib/stores/organization';
import { type SMTPSecure } from '@appwrite.io/console';
import InputSelect from '$lib/elements/forms/inputSelect.svelte';
import { upgradeURL } from '$lib/stores/billing';
import { isFreeTier, upgradeURL } from '$lib/stores/billing';
let enabled = false;
let senderName: string;
@@ -132,7 +132,7 @@
class="link">here</a>
</p>
<svelte:fragment slot="aside">
{#if $organization.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization.billingPlan)}
<Alert type="info">
Custom SMTP is a Pro plan feature. Upgrade to enable custom SMTP sever.
<svelte:fragment slot="action">
@@ -204,9 +204,7 @@
{/if}
</svelte:fragment>
<svelte:fragment slot="actions">
<Button
submit
disabled={isButtonDisabled || $organization.billingPlan === BillingPlan.FREE}>
<Button submit disabled={isButtonDisabled || isFreeTier($organization.billingPlan)}>
Update
</Button>
</svelte:fragment>
@@ -10,7 +10,7 @@
Table,
TableRowLink
} from '$lib/elements/table';
import { showUsageRatesModal, tierToPlan, upgradeURL } from '$lib/stores/billing';
import { isFreeTier, showUsageRatesModal, tierToPlan, upgradeURL } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { Button } from '$lib/elements/forms';
import { bytesToSize, humanFileSize, mbSecondsToGBHours } from '$lib/helpers/sizeConvertion';
@@ -66,7 +66,7 @@
<div class="u-flex u-cross-center u-main-space-between">
<Heading tag="h2" size="5">Usage</Heading>
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<Button href={$upgradeURL}>
<span class="text">Upgrade</span>
</Button>
@@ -87,7 +87,7 @@
on:click={() => ($showUsageRatesModal = true)}
link>Learn more about plan usage limits.</Button>
</p>
{:else if $organization.billingPlan === BillingPlan.FREE}
{:else if isFreeTier($organization.billingPlan)}
<p class="text">
If you exceed the limits of the {plan} plan, services for your projects may be disrupted.
<a href={$upgradeURL} class="link">Upgrade for greater capacity</a>.
@@ -1,11 +1,10 @@
<script lang="ts">
import { Submit } from '$lib/actions/analytics';
import { Alert, CardGrid, Heading } from '$lib/components';
import { BillingPlan } from '$lib/constants';
import { Button, Form, FormItem, InputNumber, InputSelect } from '$lib/elements/forms';
import { humanFileSize, sizeToBytes } from '$lib/helpers/sizeConvertion';
import { createByteUnitPair } from '$lib/helpers/unit';
import { readOnly, upgradeURL } from '$lib/stores/billing';
import { isFreeTier, readOnly, upgradeURL } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { GRACE_PERIOD_OVERRIDE, isCloud } from '$lib/system';
import { bucket } from '../store';
@@ -47,12 +46,12 @@
The {currentPlan.name} plan has a maximum upload file size limit of {Math.floor(
parseInt(size.value)
)}{size.unit}.
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
Upgrade to allow files of a larger size.
{/if}
</p>
<svelte:fragment slot="action">
{#if $organization?.billingPlan === BillingPlan.FREE}
{#if isFreeTier($organization?.billingPlan)}
<div class="alert-buttons u-flex">
<Button text href={$upgradeURL}>Upgrade plan</Button>
</div>