feat: add limitReached banner and delete previous modal

This commit is contained in:
Arman
2024-04-05 16:56:05 +02:00
parent a95d1ed38d
commit 04ac6cc5cf
8 changed files with 74 additions and 130 deletions
@@ -0,0 +1,43 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import { trackEvent } from '$lib/actions/analytics';
import { BillingPlan } from '$lib/constants';
import { Button } from '$lib/elements/forms';
import { HeaderAlert } from '$lib/layout';
import { readOnly, tierToPlan } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { wizard } from '$lib/stores/wizard';
import ChangeOrganizationTierCloud from '$routes/console/changeOrganizationTierCloud.svelte';
</script>
{#if $organization?.$id && $organization?.billingPlan === BillingPlan.STARTER && $readOnly && !$page.url.pathname.includes('/console/account')}
<HeaderAlert
type="error"
title={`${$organization.name} usage has reached the ${tierToPlan($organization.billingPlan).name} plan limit`}>
<svelte:fragment>
Usage for the <b>{$organization.name}</b> organization has reached the limits of the Starter
plan. Consider upgrading to increase your resource usage.
</svelte:fragment>
<svelte:fragment slot="buttons">
<Button
href={`${base}/console/organization-${$organization?.$id}/usage`}
text
fullWidthMobile>
<span class="text">View usage</span>
</Button>
<Button
on:click={() => {
wizard.start(ChangeOrganizationTierCloud);
trackEvent('click_organization_upgrade', {
from: 'button',
source: 'limit_reached_banner'
});
}}
secondary
fullWidthMobile>
<span class="text">Upgrade plan</span>
</Button>
</svelte:fragment>
</HeaderAlert>
{/if}
-14
View File
@@ -24,9 +24,6 @@
import CreateOrganizationCloud from '$routes/console/createOrganizationCloud.svelte';
import { Feedback } from '$lib/components/feedback';
import ChangeOrganizationTierCloud from '$routes/console/changeOrganizationTierCloud.svelte';
import { Pill } from '$lib/elements';
import { showExcess } from '$routes/console/organization-[organization]/store';
import { readOnly } from '$lib/stores/billing';
import { BillingPlan } from '$lib/constants';
let showDropdown = false;
@@ -105,17 +102,6 @@
<svelte:component this={$page.data.breadcrumbs} />
{/if}
{#if !$page.url.pathname.includes('/console/account') && $readOnly}
<div style="min-inline-size: fit-content">
<Pill danger button on:click={() => ($showExcess = true)}>
<div>
<span class="icon-exclamation-circle" aria-hidden="true" />
<span>limit reached</span>
</div>
</Pill>
</div>
{/if}
<div class="main-header-end">
<nav class="u-flex is-only-desktop u-cross-center">
{#if isCloud && $organization?.billingPlan === BillingPlan.STARTER && !$page.url.pathname.startsWith('/console/account')}
+23 -1
View File
@@ -23,6 +23,7 @@ import MarkedForDeletion from '$lib/components/billing/alerts/markedForDeletion.
import { BillingPlan } from '$lib/constants';
import PaymentMandate from '$lib/components/billing/alerts/paymentMandate.svelte';
import MissingPaymentMethod from '$lib/components/billing/alerts/missingPaymentMethod.svelte';
import LimitReached from '$lib/components/billing/alerts/limitReached.svelte';
export type Tier = 'tier-0' | 'tier-1' | 'tier-2';
@@ -179,6 +180,10 @@ export function calculateTrialDay(org: Organization) {
}
export async function checkForUsageLimit(org: Organization) {
if (org.billingPlan !== BillingPlan.STARTER) {
readOnly.set(false);
return;
}
if (!org?.billingLimits) {
readOnly.set(false);
return;
@@ -198,7 +203,24 @@ export async function checkForUsageLimit(org: Organization) {
membersOverflow > 0
) {
readOnly.set(true);
} else readOnly.set(false);
headerAlert.add({
id: 'limitReached',
component: LimitReached,
show: true,
importance: 7
});
} else if (
bandwidth >= 75 ||
documents >= 75 ||
executions >= 75 ||
storage >= 75 ||
users >= 75
) {
readOnly.set(false);
//show notification
} else {
readOnly.set(false);
}
}
export async function checkPaymentAuthorizationRequired(org: Organization) {
+1 -5
View File
@@ -37,8 +37,7 @@
import { stripe } from '$lib/stores/stripe';
import MobileSupportModal from './wizard/support/mobileSupportModal.svelte';
import { showSupportModal } from './wizard/support/store';
import ExcesLimitModal from './organization-[organization]/excesLimitModal.svelte';
import { showExcess } from './organization-[organization]/store';
import UsageRates from './wizard/cloudOrganization/usageRates.svelte';
import { activeHeaderAlert, consoleVariables } from './store';
import { headerAlert } from '$lib/stores/headerAlert';
@@ -325,9 +324,6 @@
<MobileSupportModal bind:show={$showSupportModal}></MobileSupportModal>
{/if}
{#if isCloud && $showExcess}
<ExcesLimitModal bind:show={$showExcess}></ExcesLimitModal>
{/if}
{#if isCloud && $showUsageRatesModal}
<UsageRates bind:show={$showUsageRatesModal} tier={$organization?.billingPlan} />
{/if}
@@ -1,106 +0,0 @@
<script lang="ts">
import { Modal } from '$lib/components';
import { sizeToBytes } from '$lib/helpers/sizeConvertion';
import { plansInfo, tierToPlan } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { onMount } from 'svelte';
import PlanExcess from '../wizard/cloudOrganizationChangeTier/planExcess.svelte';
import type { OrganizationUsage } from '$lib/sdk/billing';
import type { Models } from '@appwrite.io/console';
import { sdk } from '$lib/stores/sdk';
import { Button } from '$lib/elements/forms';
import { wizard } from '$lib/stores/wizard';
import ChangeOrganizationTierCloud from '../changeOrganizationTierCloud.svelte';
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);
let usage: OrganizationUsage = null;
let members: Models.MembershipList = null;
let excess: Record<string, number> = null;
onMount(async () => {
usage = await sdk.forConsole.billing.listUsage(
$organization.$id,
$organization.billingCurrentInvoiceDate,
new Date().toISOString()
);
members = await sdk.forConsole.teams.listMemberships($organization.$id);
calculateExcess();
});
function calculateExcess() {
const totBandwidth = usage?.bandwidth?.length > 0 ? last(usage.bandwidth).value : 0;
const totUsers = usage?.users?.length > 0 ? last(usage.users).value : 0;
excess = {
bandwidth: totBandwidth > plan.bandwidth ? totBandwidth - plan.bandwidth : 0,
storage:
usage?.storageTotal > sizeToBytes(plan.storage, 'GB')
? usage.storageTotal - sizeToBytes(plan.storage, 'GB')
: 0,
users: totUsers > (plan.users || Infinity) ? totUsers - plan.users : 0,
executions:
usage?.executionsTotal > sizeToBytes(plan.executions, 'GB')
? usage.executionsTotal - sizeToBytes(plan.executions, 'GB')
: 0,
members:
members?.total > (plan.members || Infinity)
? members.total - (plan.members || Infinity)
: 0
};
}
$: if (show) calculateExcess();
</script>
<Modal bind:show title="Limit reached">
<svelte:fragment slot="title">
Your usage exceeds the {tierToPlan($organization.billingPlan).name} plan limits
</svelte:fragment>
{#if $organization.billingPlan === BillingPlan.STARTER}
<p class="text">
Usage for <b>{$organization.name}</b> organization has reached the limits of the {tierToPlan(
$organization.billingPlan
).name} plan. Consider upgrading to increase your resource usage.
</p>
{:else}
<p class="text">
Usage for <b>{$organization.name}</b> organization has reached the limits of the {tierToPlan(
$organization.billingPlan
).name} plan. Excess usage fees will apply.
</p>
{/if}
<PlanExcess {excess} currentTier={$organization.billingPlan} />
<svelte:fragment slot="footer">
<div class="u-flex u-main-space-between u-width-full-line">
<Button text on:click={() => (show = false)}>Cancel</Button>
<div class="u-flex u-main-end u-gap-16">
<Button
secondary
on:click={() => {
show = false;
goto(`/console/organization-${$organization.$id}/usage`);
}}>
View usage
</Button>
<Button
on:click={() => {
show = false;
wizard.start(ChangeOrganizationTierCloud);
trackEvent('click_organization_upgrade', {
from: 'button',
source: 'limit_reached_modal'
});
}}>
Upgrade plan
</Button>
</div>
</div>
</svelte:fragment>
</Modal>
@@ -1,6 +1,5 @@
import { page } from '$app/stores';
import type { Models } from '@appwrite.io/console';
import { derived, writable } from 'svelte/store';
import { derived } from 'svelte/store';
export const showExcess = writable<boolean>(false);
export const projects = derived(page, ($page) => $page.data?.projects as Models.ProjectList);
@@ -107,7 +107,8 @@
<Heading tag="h6" size="7">Bandwidth</Heading>
<p class="text">
Calculated for all bandwidth used across all projects in your organization.
Calculated for all bandwidth used across all projects in your organization. Resets at
the start of each billing cycle.
</p>
<svelte:fragment slot="aside">
@@ -104,7 +104,10 @@
</div>
<CardGrid>
<Heading tag="h4" size="7">Bandwidth</Heading>
<p class="text">Calculated for all bandwidth used in your project.</p>
<p class="text">
Calculated for all bandwidth used across your project. Resets at the start of each
billing cycle.
</p>
<svelte:fragment slot="aside">
{#if network}
{@const humanized = humanFileSize(total(network))}