From c1e87a2540e09b196f2ba33c7abfa1ff9ba82c69 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 16 Dec 2024 11:39:13 +0530 Subject: [PATCH 1/4] updated pricing. --- .../billing/estimatedTotalBox.svelte | 90 ++++++++++++++----- .../change-plan/+page.svelte | 13 +-- 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/src/lib/components/billing/estimatedTotalBox.svelte b/src/lib/components/billing/estimatedTotalBox.svelte index b7ab73af7..df06ef0b7 100644 --- a/src/lib/components/billing/estimatedTotalBox.svelte +++ b/src/lib/components/billing/estimatedTotalBox.svelte @@ -5,7 +5,11 @@ import type { Coupon } from '$lib/sdk/billing'; import { plansInfo, type Tier } from '$lib/stores/billing'; import { CreditsApplied } from '.'; + import { BillingPlan } from '$lib/constants'; + import { tooltip } from '$lib/actions/tooltip'; + // undefined as we only need this on `change-plan` + export let currentTier: Tier | undefined = undefined; export let billingPlan: Tier; export let collaborators: string[]; export let couponData: Partial; @@ -14,22 +18,33 @@ export let isDowngrade = false; const today = new Date(); + const isScaleDowngrade = isDowngrade && billingPlan === BillingPlan.PRO; + const isScaleUpgrade = !isDowngrade && billingPlan === BillingPlan.SCALE; const billingPayDate = new Date(today.getTime() + 30 * 24 * 60 * 60 * 1000); let budgetEnabled = false; - $: currentPlan = $plansInfo.get(billingPlan); - $: extraSeatsCost = 0; // 0 untile trial period later replace (collaborators?.length ?? 0) * (currentPlan?.addons?.member?.price ?? 0); - $: grossCost = currentPlan.price + extraSeatsCost; + $: selectedPlan = $plansInfo.get(billingPlan); + $: currentOrgPlan = $plansInfo.get(currentTier); + $: unUsedBalances = isScaleUpgrade + ? currentOrgPlan.price + + (collaborators?.length ?? 0) * (currentOrgPlan?.addons?.member?.price ?? 0) + : isScaleDowngrade + ? currentOrgPlan.price + : 0; + + $: extraSeatsCost = (collaborators?.length ?? 0) * (selectedPlan?.addons?.member?.price ?? 0); + $: grossCost = + isScaleUpgrade || isScaleDowngrade + ? selectedPlan.price + extraSeatsCost - unUsedBalances + : selectedPlan.price + extraSeatsCost; $: estimatedTotal = - couponData?.status === 'active' - ? grossCost - couponData.credits >= 0 - ? grossCost - couponData.credits - : 0 - : grossCost; + couponData?.status === 'active' ? Math.max(0, grossCost - couponData.credits) : grossCost; $: trialEndDate = new Date( - billingPayDate.getTime() + currentPlan.trialDays * 24 * 60 * 60 * 1000 + billingPayDate.getTime() + selectedPlan.trialDays * 24 * 60 * 60 * 1000 ); + + $: isRefund = isScaleDowngrade && grossCost < 0;
- -

{currentPlan.name} plan

-

{formatCurrency(currentPlan.price)}

-
- +
+

{selectedPlan.name} plan

+

{formatCurrency(selectedPlan.price)}

+
+ +

Additional seats ({collaborators?.length})

- {formatCurrency(extraSeatsCost)} + {formatCurrency( + isScaleDowngrade + ? (collaborators?.length ?? 0) * (selectedPlan?.addons?.member?.price ?? 0) + : extraSeatsCost + )}

- +
+ + {#if isScaleUpgrade} + {@const currentPlanName = currentOrgPlan.name} +
+
+ Unused {currentPlanName} plan balance + + +
+

-{formatCurrency(unUsedBalances)}

+
+ {:else if isScaleDowngrade} +
+ Unused {currentOrgPlan.name} plan balance +

-{formatCurrency(currentOrgPlan.price)}

+
+ {/if} + {#if couponData?.status === 'active'} {/if}
- +

Upcoming charge
Due on {!currentPlan.trialDays + >Due on {!selectedPlan.trialDays ? toLocaleDate(billingPayDate.toString()) : toLocaleDate(trialEndDate.toString())}

{formatCurrency(estimatedTotal)}

- +

- You'll pay {formatCurrency(estimatedTotal)} now, with our first - billing cycle starting on + You'll {isRefund ? 'receive a refund of' : 'pay'} + {formatCurrency(estimatedTotal)} + now, with our first billing cycle starting on {!currentPlan.trialDays + >{!selectedPlan.trialDays ? toLocaleDate(billingPayDate.toString()) : toLocaleDate(trialEndDate.toString())}. Once your credits run out, you'll be charged - {formatCurrency(currentPlan.price)} plus usage fees every 30 days. + {formatCurrency(selectedPlan.price)} plus usage fees every 30 days.

diff --git a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte index fe317b18a..46c1e8b59 100644 --- a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte +++ b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte @@ -23,7 +23,7 @@ InputTextarea, Label } from '$lib/elements/forms'; - import { formatCurrency } from '$lib/helpers/numbers.js'; + import { formatCurrency } from '$lib/helpers/numbers'; import { WizardSecondaryContainer, WizardSecondaryContent, @@ -39,7 +39,7 @@ type OrganizationError } from '$lib/stores/organization'; import { sdk } from '$lib/stores/sdk'; - import { confirmPayment } from '$lib/stores/stripe.js'; + import { confirmPayment } from '$lib/stores/stripe'; import { user } from '$lib/stores/user'; import { VARS } from '$lib/system'; import { onMount } from 'svelte'; @@ -107,8 +107,8 @@ billingPlan = BillingPlan.PRO; } - const currentPlan = await sdk.forConsole.billing.getPlan($organization?.$id); - selfService = currentPlan.selfService; + const currentOrgPlan = await sdk.forConsole.billing.getPlan($organization?.$id); + selfService = currentOrgPlan.selfService; }); async function loadPaymentMethods() { @@ -210,7 +210,7 @@ async function upgrade() { try { //Add collaborators - var newCollaborators = []; + let newCollaborators = []; if (collaborators?.length) { newCollaborators = collaborators.filter( (collaborator) => @@ -369,11 +369,12 @@ {#if billingPlan !== BillingPlan.FREE && $organization.billingPlan !== billingPlan && $organization.billingPlan !== BillingPlan.CUSTOM} + currentTier={$organization.billingPlan} /> {:else if $organization.billingPlan !== BillingPlan.CUSTOM} {/if} From bcbf5c75b5faa7ee1b82b3c0192949d586774809 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 19 Dec 2024 13:25:27 +0530 Subject: [PATCH 2/4] address comments. --- .../billing/estimatedTotalBox.svelte | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/lib/components/billing/estimatedTotalBox.svelte b/src/lib/components/billing/estimatedTotalBox.svelte index df06ef0b7..b73c87378 100644 --- a/src/lib/components/billing/estimatedTotalBox.svelte +++ b/src/lib/components/billing/estimatedTotalBox.svelte @@ -34,17 +34,14 @@ : 0; $: extraSeatsCost = (collaborators?.length ?? 0) * (selectedPlan?.addons?.member?.price ?? 0); - $: grossCost = - isScaleUpgrade || isScaleDowngrade - ? selectedPlan.price + extraSeatsCost - unUsedBalances - : selectedPlan.price + extraSeatsCost; + $: grossCost = isScaleUpgrade + ? selectedPlan.price + extraSeatsCost - unUsedBalances + : selectedPlan.price + extraSeatsCost; $: estimatedTotal = couponData?.status === 'active' ? Math.max(0, grossCost - couponData.credits) : grossCost; $: trialEndDate = new Date( billingPayDate.getTime() + selectedPlan.trialDays * 24 * 60 * 60 * 1000 ); - - $: isRefund = isScaleDowngrade && grossCost < 0;

-{formatCurrency(unUsedBalances)}

- {:else if isScaleDowngrade} -
- Unused {currentOrgPlan.name} plan balance -

-{formatCurrency(currentOrgPlan.price)}

-
{/if} {#if couponData?.status === 'active'} @@ -107,15 +99,28 @@

- You'll {isRefund ? 'receive a refund of' : 'pay'} - {formatCurrency(estimatedTotal)} - now, with our first billing cycle starting on - {!selectedPlan.trialDays - ? toLocaleDate(billingPayDate.toString()) - : toLocaleDate(trialEndDate.toString())}. Once your credits run out, you'll be charged - {formatCurrency(selectedPlan.price)} plus usage fees every 30 days. + {#if isScaleDowngrade} + You'll continue using the {currentOrgPlan.name} plan until your current cycle ends on + {!selectedPlan.trialDays + ? toLocaleDate(billingPayDate.toString()) + : toLocaleDate(trialEndDate.toString())}. Starting the next cycle, your plan will switch to {selectedPlan.name}, and you'll be + charged + {formatCurrency(grossCost)} + every 30 days. + {:else} + You'll pay + {formatCurrency(estimatedTotal)} + now, with our first billing cycle starting on + {!selectedPlan.trialDays + ? toLocaleDate(billingPayDate.toString()) + : toLocaleDate(trialEndDate.toString())}. Once your credits run out, you'll be charged + {formatCurrency(selectedPlan.price)} plus usage fees every 30 + days. + {/if}

From b6a517a8cf952c9d3ba5d982a34e7c4f23935dff Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 19 Dec 2024 13:25:35 +0530 Subject: [PATCH 3/4] ran: formatter. --- src/lib/components/billing/planSelection.svelte | 6 +----- src/lib/sdk/billing.ts | 7 ++----- src/lib/stores/stripe.ts | 4 ++-- src/routes/(console)/account/organizations/+page.ts | 10 ++++------ src/routes/+layout.ts | 4 +++- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/lib/components/billing/planSelection.svelte b/src/lib/components/billing/planSelection.svelte index cfcb28bba..4a6e1f7ca 100644 --- a/src/lib/components/billing/planSelection.svelte +++ b/src/lib/components/billing/planSelection.svelte @@ -77,11 +77,7 @@
  • - +

    diff --git a/src/lib/sdk/billing.ts b/src/lib/sdk/billing.ts index bee94ffc3..57ad227be 100644 --- a/src/lib/sdk/billing.ts +++ b/src/lib/sdk/billing.ts @@ -318,14 +318,11 @@ export class Billing { ); } - async validateOrganization( - organizationId: string, - invites: string[], - ): Promise { + async validateOrganization(organizationId: string, invites: string[]): Promise { const path = `/organizations/${organizationId}/validate`; const params = { organizationId, - invites, + invites }; const uri = new URL(this.client.config.endpoint + path); return await this.client.call( diff --git a/src/lib/stores/stripe.ts b/src/lib/stores/stripe.ts index 357974646..e62110d20 100644 --- a/src/lib/stores/stripe.ts +++ b/src/lib/stores/stripe.ts @@ -130,8 +130,8 @@ export async function confirmPayment( clientSecret: clientSecret, confirmParams: { return_url: url, - payment_method: paymentMethod.providerMethodId, - }, + payment_method: paymentMethod.providerMethodId + } }); if (error) { if (returnError) { diff --git a/src/routes/(console)/account/organizations/+page.ts b/src/routes/(console)/account/organizations/+page.ts index 803497c6a..237a3772d 100644 --- a/src/routes/(console)/account/organizations/+page.ts +++ b/src/routes/(console)/account/organizations/+page.ts @@ -10,13 +10,11 @@ export const load: PageLoad = async ({ url, route }) => { const limit = getLimit(url, route, CARD_LIMIT); const offset = pageToOffset(page, limit); - const queries = [ - Query.offset(offset), - Query.limit(limit), - Query.orderDesc('') - ]; + const queries = [Query.offset(offset), Query.limit(limit), Query.orderDesc('')]; - const organizations = isCloud ? await sdk.forConsole.billing.listOrganization(queries) : sdk.forConsole.teams.list(queries); + const organizations = isCloud + ? await sdk.forConsole.billing.listOrganization(queries) + : sdk.forConsole.teams.list(queries); return { offset, diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index 6468cab57..4c9b760ca 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -29,7 +29,9 @@ export const load: LayoutLoad = async ({ depends, url, route }) => { if (account) { return { account, - organizations: isCloud ? await sdk.forConsole.billing.listOrganization() : await sdk.forConsole.teams.list() + organizations: isCloud + ? await sdk.forConsole.billing.listOrganization() + : await sdk.forConsole.teams.list() }; } From 34f0727d5fc3689fb75c19dcf45113487c41fc35 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 9 Jan 2025 11:48:59 +0530 Subject: [PATCH 4/4] ci: empty commit