From 04ac6cc5cf97dd2561dce33036abd5e349cca504 Mon Sep 17 00:00:00 2001 From: Arman Date: Fri, 5 Apr 2024 16:56:05 +0200 Subject: [PATCH 1/5] feat: add `limitReached` banner and delete previous modal --- .../billing/alerts/limitReached.svelte | 43 +++++++ src/lib/layout/header.svelte | 14 --- src/lib/stores/billing.ts | 24 +++- src/routes/console/+layout.svelte | 6 +- .../excesLimitModal.svelte | 106 ------------------ .../organization-[organization]/store.ts | 3 +- .../usage/[[invoice]]/+page.svelte | 3 +- .../settings/usage/[[invoice]]/+page.svelte | 5 +- 8 files changed, 74 insertions(+), 130 deletions(-) create mode 100644 src/lib/components/billing/alerts/limitReached.svelte delete mode 100644 src/routes/console/organization-[organization]/excesLimitModal.svelte diff --git a/src/lib/components/billing/alerts/limitReached.svelte b/src/lib/components/billing/alerts/limitReached.svelte new file mode 100644 index 000000000..9844136b6 --- /dev/null +++ b/src/lib/components/billing/alerts/limitReached.svelte @@ -0,0 +1,43 @@ + + +{#if $organization?.$id && $organization?.billingPlan === BillingPlan.STARTER && $readOnly && !$page.url.pathname.includes('/console/account')} + + + Usage for the {$organization.name} organization has reached the limits of the Starter + plan. Consider upgrading to increase your resource usage. + + + + + + +{/if} diff --git a/src/lib/layout/header.svelte b/src/lib/layout/header.svelte index 9dbc534c5..16c97001a 100644 --- a/src/lib/layout/header.svelte +++ b/src/lib/layout/header.svelte @@ -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 @@ {/if} -{#if !$page.url.pathname.includes('/console/account') && $readOnly} -
- ($showExcess = true)}> -
-
-
-
-{/if} -
Bandwidth -

Calculated for all bandwidth used in your project.

+

+ Calculated for all bandwidth used across your project. Resets at the start of each + billing cycle. +

{#if network} {@const humanized = humanFileSize(total(network))} From ada46586e8a547ba117b82e6acf82cf7b2e24d1e Mon Sep 17 00:00:00 2001 From: Arman Date: Fri, 5 Apr 2024 17:15:17 +0200 Subject: [PATCH 2/5] feat: add notificaiton for when a service is over the 75% mark --- src/lib/stores/billing.ts | 62 +++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts index 8155f4a4a..50f03d7a4 100644 --- a/src/lib/stores/billing.ts +++ b/src/lib/stores/billing.ts @@ -24,6 +24,10 @@ 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'; +import { wizard } from './wizard'; +import ChangeOrganizationTierCloud from '$routes/console/changeOrganizationTierCloud.svelte'; +import { trackEvent } from '$lib/actions/analytics'; +import { browser } from '$app/environment'; export type Tier = 'tier-0' | 'tier-1' | 'tier-2'; @@ -189,19 +193,20 @@ export async function checkForUsageLimit(org: Organization) { return; } const { bandwidth, documents, executions, storage, users } = org?.billingLimits ?? {}; + const resources = [ + { value: bandwidth, name: 'bandwidth' }, + { value: documents, name: 'documents' }, + { value: executions, name: 'executions' }, + { value: storage, name: 'storage' }, + { value: users, name: 'users' } + ]; + const members = await sdk.forConsole.teams.listMemberships(org.$id); const plan = get(plansInfo)?.get(org.billingPlan); const membersOverflow = members?.total > plan.members ? members.total - (plan.members || members.total) : 0; - if ( - bandwidth >= 100 || - documents >= 100 || - executions >= 100 || - storage >= 100 || - users >= 100 || - membersOverflow > 0 - ) { + if (resources.some((r) => r.value >= 100) || membersOverflow > 0) { readOnly.set(true); headerAlert.add({ id: 'limitReached', @@ -209,15 +214,40 @@ export async function checkForUsageLimit(org: Organization) { show: true, importance: 7 }); - } else if ( - bandwidth >= 75 || - documents >= 75 || - executions >= 75 || - storage >= 75 || - users >= 75 - ) { + } else if (resources.some((r) => r.value >= 75)) { readOnly.set(false); - //show notification + if (browser) { + const lastNotification = + parseInt(localStorage.getItem('limitReachedNotification')) ?? 0; + const now = new Date().getTime(); + if (now - lastNotification < 1000 * 60 * 60 * 24 * 3) return; + + localStorage.setItem('limitReachedNotification', now.toString()); + addNotification({ + type: 'warning', + isHtml: true, + timeout: 0, + message: `${org.name} has reached 75% of the Starter plan's ${resources.find((r) => r.value >= 75).name} limit. Upgrade to ensure there are no service disruptions.`, + buttons: [ + { + name: 'View usage', + method: () => { + goto(`${base}/console/organization-${org.$id}/usage`); + } + }, + { + name: 'Upgrade plan', + method: () => { + wizard.start(ChangeOrganizationTierCloud); + trackEvent('click_organization_upgrade', { + from: 'button', + source: 'limit_reached_notification' + }); + } + } + ] + }); + } } else { readOnly.set(false); } From 330a447196011ec3841b7431807bcc135265d505 Mon Sep 17 00:00:00 2001 From: Arman Date: Mon, 8 Apr 2024 13:26:41 +0200 Subject: [PATCH 3/5] feat: show notification once a day --- src/lib/stores/billing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts index 50f03d7a4..362dcdf6e 100644 --- a/src/lib/stores/billing.ts +++ b/src/lib/stores/billing.ts @@ -220,7 +220,7 @@ export async function checkForUsageLimit(org: Organization) { const lastNotification = parseInt(localStorage.getItem('limitReachedNotification')) ?? 0; const now = new Date().getTime(); - if (now - lastNotification < 1000 * 60 * 60 * 24 * 3) return; + if (now - lastNotification < 1000 * 60 * 60 * 24) return; localStorage.setItem('limitReachedNotification', now.toString()); addNotification({ From 6e09e6cc756de7d58e984b2692737c26e062bfa8 Mon Sep 17 00:00:00 2001 From: Arman Date: Mon, 8 Apr 2024 13:32:18 +0200 Subject: [PATCH 4/5] feat: update message --- src/lib/stores/billing.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts index 362dcdf6e..be97eab8a 100644 --- a/src/lib/stores/billing.ts +++ b/src/lib/stores/billing.ts @@ -223,11 +223,15 @@ export async function checkForUsageLimit(org: Organization) { if (now - lastNotification < 1000 * 60 * 60 * 24) return; localStorage.setItem('limitReachedNotification', now.toString()); + let message = `${org.name} has reached 75% of the Starter plan's ${resources.find((r) => r.value >= 75).name} limit. Upgrade to ensure there are no service disruptions.`; + if (resources.filter((r) => r.value >= 75)?.length > 1) { + message = `Usage for ${org.name} has reached 75% of the Starter plan limit. Upgrade to ensure there are no service disruptions.`; + } addNotification({ type: 'warning', isHtml: true, timeout: 0, - message: `${org.name} has reached 75% of the Starter plan's ${resources.find((r) => r.value >= 75).name} limit. Upgrade to ensure there are no service disruptions.`, + message, buttons: [ { name: 'View usage', From 01f1d4f6621707fdf19cf3c2fdca85777d9a5b5f Mon Sep 17 00:00:00 2001 From: Arman Date: Tue, 9 Apr 2024 16:26:55 +0200 Subject: [PATCH 5/5] chore: remove browser check --- src/lib/stores/billing.ts | 66 ++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts index be97eab8a..3d827cf5c 100644 --- a/src/lib/stores/billing.ts +++ b/src/lib/stores/billing.ts @@ -27,7 +27,6 @@ import LimitReached from '$lib/components/billing/alerts/limitReached.svelte'; import { wizard } from './wizard'; import ChangeOrganizationTierCloud from '$routes/console/changeOrganizationTierCloud.svelte'; import { trackEvent } from '$lib/actions/analytics'; -import { browser } from '$app/environment'; export type Tier = 'tier-0' | 'tier-1' | 'tier-2'; @@ -216,42 +215,39 @@ export async function checkForUsageLimit(org: Organization) { }); } else if (resources.some((r) => r.value >= 75)) { readOnly.set(false); - if (browser) { - const lastNotification = - parseInt(localStorage.getItem('limitReachedNotification')) ?? 0; - const now = new Date().getTime(); - if (now - lastNotification < 1000 * 60 * 60 * 24) return; + const lastNotification = parseInt(localStorage.getItem('limitReachedNotification')) ?? 0; + const now = new Date().getTime(); + if (now - lastNotification < 1000 * 60 * 60 * 24) return; - localStorage.setItem('limitReachedNotification', now.toString()); - let message = `${org.name} has reached 75% of the Starter plan's ${resources.find((r) => r.value >= 75).name} limit. Upgrade to ensure there are no service disruptions.`; - if (resources.filter((r) => r.value >= 75)?.length > 1) { - message = `Usage for ${org.name} has reached 75% of the Starter plan limit. Upgrade to ensure there are no service disruptions.`; - } - addNotification({ - type: 'warning', - isHtml: true, - timeout: 0, - message, - buttons: [ - { - name: 'View usage', - method: () => { - goto(`${base}/console/organization-${org.$id}/usage`); - } - }, - { - name: 'Upgrade plan', - method: () => { - wizard.start(ChangeOrganizationTierCloud); - trackEvent('click_organization_upgrade', { - from: 'button', - source: 'limit_reached_notification' - }); - } - } - ] - }); + localStorage.setItem('limitReachedNotification', now.toString()); + let message = `${org.name} has reached 75% of the Starter plan's ${resources.find((r) => r.value >= 75).name} limit. Upgrade to ensure there are no service disruptions.`; + if (resources.filter((r) => r.value >= 75)?.length > 1) { + message = `Usage for ${org.name} has reached 75% of the Starter plan limit. Upgrade to ensure there are no service disruptions.`; } + addNotification({ + type: 'warning', + isHtml: true, + timeout: 0, + message, + buttons: [ + { + name: 'View usage', + method: () => { + goto(`${base}/console/organization-${org.$id}/usage`); + } + }, + { + name: 'Upgrade plan', + method: () => { + wizard.start(ChangeOrganizationTierCloud); + trackEvent('click_organization_upgrade', { + from: 'button', + source: 'limit_reached_notification' + }); + } + } + ] + }); } else { readOnly.set(false); }