diff --git a/src/lib/commandCenter/panels/ai.svelte b/src/lib/commandCenter/panels/ai.svelte index 357c90f6b..5f8a06ee3 100644 --- a/src/lib/commandCenter/panels/ai.svelte +++ b/src/lib/commandCenter/panels/ai.svelte @@ -1,11 +1,11 @@ - - - - - {#if couponData?.status === 'error'} + + + +{#if couponData?.status === 'error'} +
+ + + {couponData.code.toUpperCase()} is not a valid promo code + +
+{:else if couponData?.status === 'active'} +
- - - {couponData.code.toUpperCase()} is not a valid promo code - + + + + {couponData.code.toUpperCase()} applied (-{formatCurrency(couponData.credits)}) + +
- {:else if couponData?.status === 'active'} -
-
- - - - {couponData.code.toUpperCase()} applied (-{formatCurrency( - couponData.credits - )}) - - -
- -
- {/if} - + +
+{/if} diff --git a/src/lib/components/billing/emptyCardCloud.svelte b/src/lib/components/billing/emptyCardCloud.svelte index 0ebb12d05..b83676f28 100644 --- a/src/lib/components/billing/emptyCardCloud.svelte +++ b/src/lib/components/billing/emptyCardCloud.svelte @@ -3,6 +3,7 @@ import { BillingPlan } from '$lib/constants'; import { Button } from '$lib/elements/forms'; import { tierToPlan, upgradeURL } from '$lib/stores/billing'; + import { Layout, Typography } from '@appwrite.io/pink-svelte'; import { Card } from '..'; export let service: string; @@ -11,14 +12,13 @@ -
-
Upgrade to add {service}
-

+ + Upgrade to add {service} + Upgrade to a {tierToPlan(BillingPlan.PRO).name} plan to add {service} to your organization -

+ -
+
diff --git a/src/lib/components/billing/paymentBoxes.svelte b/src/lib/components/billing/paymentBoxes.svelte index 0c5c05e64..be241fdf7 100644 --- a/src/lib/components/billing/paymentBoxes.svelte +++ b/src/lib/components/billing/paymentBoxes.svelte @@ -94,12 +94,10 @@
{#if showSetAsDefault} - + {/if} {/if} diff --git a/src/lib/components/billing/paymentModal.svelte b/src/lib/components/billing/paymentModal.svelte index d8fed82af..10b7ae6b7 100644 --- a/src/lib/components/billing/paymentModal.svelte +++ b/src/lib/components/billing/paymentModal.svelte @@ -66,29 +66,25 @@ - - - + + -
- - {#if isLoading} - - {/if} +
+ {#if isLoading} + + {/if} -
- -
- +
+
- - +
+ @@ -98,7 +94,7 @@ +
+ diff --git a/src/lib/components/billing/planExcess.svelte b/src/lib/components/billing/planExcess.svelte index 10fe17d54..485dbe74b 100644 --- a/src/lib/components/billing/planExcess.svelte +++ b/src/lib/components/billing/planExcess.svelte @@ -1,14 +1,4 @@ {#if showExcess} - - - Your {tierToPlan($organization.billingPlan).name} plan subscription will end on {toLocaleDate( - $organization.billingNextInvoiceDate - )} - + Following payment of your final invoice, your organization will switch to the {tierToPlan( BillingPlan.FREE ).name} plan. {#if excess?.members > 0}All team members except the owner will be removed on @@ -67,80 +58,78 @@ Learn more - + - - - Resource - Free limit - + + + Resource + Free limit + Excess usage + > Metrics are estimates updated every 24 hours - - - - {#if excess?.members} - - Organization members - {plan.members} members - -

- - {excess?.members} members -

-
-
- {/if} - {#if excess?.storage} - - Storage - {plan.storage} GB - -

- - {humanFileSize(excess?.storage).value} - {humanFileSize(excess?.storage).unit} -

-
-
- {/if} - {#if excess?.executions} - - Function executions - - {abbreviateNumber(plan.executions)} executions - - -

- - - {formatNum(excess?.executions)} executions - -

-
-
- {/if} - {#if excess?.users} - - Users - - {abbreviateNumber(plan.users)} users - - -

- - - {formatNum(excess?.users)} users - -

-
-
- {/if} -
-
+ + + {#if excess?.members} + + Organization members + {plan.members} members + +

+ + {excess?.members} members +

+
+
+ {/if} + {#if excess?.storage} + + Storage + {plan.storage} GB + +

+ + {humanFileSize(excess?.storage).value} + {humanFileSize(excess?.storage).unit} +

+
+
+ {/if} + {#if excess?.executions} + + Function executions + + {abbreviateNumber(plan.executions)} executions + + +

+ + + {formatNum(excess?.executions)} executions + +

+
+
+ {/if} + {#if excess?.users} + + Users + + {abbreviateNumber(plan.users)} users + + +

+ + + {formatNum(excess?.users)} users + +

+
+
+ {/if} + {/if} diff --git a/src/lib/components/billing/planSelection.svelte b/src/lib/components/billing/planSelection.svelte index 55e137572..e26ea88c4 100644 --- a/src/lib/components/billing/planSelection.svelte +++ b/src/lib/components/billing/planSelection.svelte @@ -3,6 +3,7 @@ import { formatCurrency } from '$lib/helpers/numbers'; import { plansInfo, type Tier, tierFree, tierPro, tierScale } from '$lib/stores/billing'; import { organization } from '$lib/stores/organization'; + import { Badge, Layout, Typography } from '@appwrite.io/pink-svelte'; import { LabelCard } from '..'; export let billingPlan: Tier; @@ -17,83 +18,60 @@ $: scalePlan = $plansInfo.get(BillingPlan.SCALE); -{#if billingPlan} -
    -
  • - -
    -

    - {tierFree.name} - {#if $organization?.billingPlan === BillingPlan.FREE && !isNewOrg} - Current plan - {/if} -

    -

    - {tierFree.description} -

    -

    - {formatCurrency(freePlan?.price ?? 0)} -

    -
    -
    -
  • - -
  • - -
    -

    - {#if $organization?.billingPlan === BillingPlan.PRO && !isNewOrg} - Current plan - {/if} -

    -

    - {tierPro.description} -

    -

    - {formatCurrency(proPlan?.price ?? 0)} per member/month + usage -

    -
    -
    -
  • -
  • - -
    -

    - {#if $organization?.billingPlan === BillingPlan.SCALE && !isNewOrg} - Current plan - {/if} -

    -

    - {tierScale.description} -

    -

    - {formatCurrency(scalePlan?.price ?? 0)} per month + usage -

    -
    -
    -
  • -
-{/if} + + + + {#if $organization?.billingPlan === BillingPlan.FREE && !isNewOrg} + + {/if} + + + {tierFree.description} + + + {formatCurrency(freePlan?.price ?? 0)} + + + + + {#if $organization?.billingPlan === BillingPlan.PRO && !isNewOrg} + + {/if} + + + {tierPro.description} + + + {formatCurrency(proPlan?.price ?? 0)} per month + usage + + + + + {#if $organization?.billingPlan === BillingPlan.SCALE && !isNewOrg} + + {/if} + + + {tierScale.description} + + + {formatCurrency(scalePlan?.price ?? 0)} per month + usage + + + diff --git a/src/lib/components/billing/selectPaymentMethod.svelte b/src/lib/components/billing/selectPaymentMethod.svelte index c81513822..dfd586ea7 100644 --- a/src/lib/components/billing/selectPaymentMethod.svelte +++ b/src/lib/components/billing/selectPaymentMethod.svelte @@ -1,14 +1,15 @@ -{#if filteredMethods?.length} - {#if selectedPaymentMethod?.country?.toLowerCase() === 'in'} - - Indian credit or debit card-holders - To comply with RBI regulations in India, Appwrite will ask for verification to charge up - to $150 USD on your payment method. We will never charge more than the cost of your plan - and the resources you use, or your budget cap limit. For higher usage limits, please contact - us. - - {/if} - { - return { - value: method.$id, - label: `${capitalize(method.brand)} ending in ${method.last4}`, - data: [method.brand] - }; - })} - interactiveOutput - let:option={o}> - - - - - - {o.label} - - - - - - - - - - - {o.label} - - - - - - - - -{:else} -
- - -
-

- - No saved payment methods -

+
+ + {#if filteredMethods?.length} + {#if selectedPaymentMethod?.country?.toLowerCase() === 'in'} + + Indian credit or debit card-holders + To comply with RBI regulations in India, Appwrite will ask for verification to charge + up to $150 USD on your payment method. We will never charge more than the cost of + your plan and the resources you use, or your budget cap limit. For higher usage limits, + please contact us. + + {/if} + { + return { + value: method.$id, + label: `${capitalize(method.brand)} ending in ${method.last4}`, + data: [method.brand] + }; + })} /> +
+
+ {:else} + + -
-
- {#if error} - {error} + {/if} -
-{/if} + + {#if showPaymentModal && isCloud && hasStripePublicKey} - - {#if showTaxId} -
- -
- {/if} -
+ bind:checked={showTaxId} /> + {#if showTaxId} + + {/if}
{/if} diff --git a/src/lib/components/billing/usageRates.svelte b/src/lib/components/billing/usageRates.svelte index b9f2f5429..c3e67be8e 100644 --- a/src/lib/components/billing/usageRates.svelte +++ b/src/lib/components/billing/usageRates.svelte @@ -1,19 +1,12 @@ - + {#if isFree} - Usage on the {$plansInfo?.get(BillingPlan.FREE).name} plan is limited for the following resources. - Next billing period: {toLocaleDate(nextDate)}. + + Usage on the {$plansInfo?.get(BillingPlan.FREE).name} plan is limited for the following resources. + Next billing period: {toLocaleDate(nextDate)}. + {:else if org.billingPlan === BillingPlan.PRO} -

+ Usage on the Pro plan will be charged at the end of each billing period at the following rates. Next billing period: {toLocaleDate(nextDate)}. -

+ {:else if org.billingPlan === BillingPlan.SCALE} -

+ Usage on the Scale plan will be charged at the end of each billing period at the following rates. Next billing period: {toLocaleDate(nextDate)}. -

+ {/if} - - - Resource - Limit + + + Resource + Limit {#if !isFree} - Rate + Rate {/if} - - - {#each planData as usage} - {#if usage['id'] === 'members'} - - {usage.resource} - - {plan[usage.id] || 'Unlimited'} - - {#if !isFree} - - {formatCurrency(plan.addons?.member?.price)}/{usage?.unit} - - {/if} - - {:else} - {@const addon = plan.addons[usage.id]} - - {usage.resource} - - {abbreviateNumber(plan[usage.id])}{usage?.unit} - - {#if !isFree} - - {formatCurrency(addon?.price)}/{['MB', 'GB', 'TB'].includes( - addon?.unit - ) - ? addon?.value - : abbreviateNumber(addon?.value, 0)}{usage?.unit} - - {/if} - - {/if} - {/each} - -
+ + {#each planData as usage} + {#if usage['id'] === 'members'} + + {usage.resource} + + {plan[usage.id] || 'Unlimited'} + + {#if !isFree} + + {formatCurrency(plan.addons?.member?.price)}/{usage?.unit} + + {/if} + + {:else} + {@const addon = plan.addons[usage.id]} + + {usage.resource} + + {abbreviateNumber(plan[usage.id])}{usage?.unit} + + {#if !isFree} + + {formatCurrency(addon?.price)}/{['MB', 'GB', 'TB'].includes(addon?.unit) + ? addon?.value + : abbreviateNumber(addon?.value, 0)}{usage?.unit} + + {/if} + + {/if} + {/each} + diff --git a/src/lib/components/billing/validateCreditModal.svelte b/src/lib/components/billing/validateCreditModal.svelte index 71775a383..9403e32f1 100644 --- a/src/lib/components/billing/validateCreditModal.svelte +++ b/src/lib/components/billing/validateCreditModal.svelte @@ -1,20 +1,20 @@ - - Credits will be applied automatically to your next invoice. + + + Credits will be applied automatically to your next invoice. + - - - + - + diff --git a/src/lib/components/labelCard.svelte b/src/lib/components/labelCard.svelte index 4995a2d12..b7c154791 100644 --- a/src/lib/components/labelCard.svelte +++ b/src/lib/components/labelCard.svelte @@ -6,7 +6,7 @@ type Props = ComponentProps; export let group: string; - export let value: string | number | boolean; + export let value: string; export let tooltipText: string = null; export let tooltipShow = false; @@ -15,6 +15,7 @@ export let imageRadius: Props['imageRadius'] = 'xxs'; export let padding: Props['padding'] = 's'; export let variant: Props['variant'] = 'primary'; + export let name: Props['name'] = undefined; //temporarily unefined export let title: Props['title'] = undefined; export let disabled = false; @@ -27,6 +28,7 @@ {#if $$slots.default} -

- -

+ {/if} +
{tooltipText}
diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 8df599504..b363b1dce 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -8,6 +8,7 @@ export enum Dependencies { CREDIT = 'dependency:credit', INVOICES = 'dependency:invoices', ADDRESS = 'dependency:address', + UPGRADE_PLAN = 'dependency:upgrade_plan', PAYMENT_METHODS = 'dependency:paymentMethods', ORGANIZATION = 'dependency:organization', MEMBERS = 'dependency:members', diff --git a/src/lib/layout/logs.svelte b/src/lib/layout/logs.svelte index 4246c8f98..7927f8aa8 100644 --- a/src/lib/layout/logs.svelte +++ b/src/lib/layout/logs.svelte @@ -3,14 +3,6 @@ import { log } from '$lib/stores/logs'; import { Alert, Card, Code, Copy, Id, SvgIcon, Tab, Tabs } from '../components'; import { calculateTime } from '$lib/helpers/timeConversion'; - import { - TableBody, - TableCellHead, - TableCellText, - TableHeader, - TableRow, - TableScroll - } from '$lib/elements/table'; import { beforeNavigate } from '$app/navigation'; import { Pill } from '$lib/elements'; import { isCloud } from '$lib/system'; @@ -18,7 +10,7 @@ import { organization } from '$lib/stores/organization'; import { Button } from '$lib/elements/forms'; import { BillingPlan } from '$lib/constants'; - import { Tooltip, Typography } from '@appwrite.io/pink-svelte'; + import { Table, Tooltip, Typography } from '@appwrite.io/pink-svelte'; let selectedRequest = 'parameters'; let selectedResponse = 'logs'; @@ -223,26 +215,22 @@
{#if selectedRequest === 'parameters'} {#if parameters?.length} -
- - - Name - Value - - - {#each parameters as param} - - - {param.key} - - - {param.value} - - - {/each} - - -
+ + + Name + Value + + {#each parameters as param} + + + {param.key} + + + {param.value} + + + {/each} + {/if}

@@ -261,26 +249,22 @@

{:else if selectedRequest === 'headers'} {#if execution.requestHeaders.length} -
- - - Name - Value - - - {#each execution.requestHeaders as header} - - - {header.name} - - - {header.value} - - - {/each} - - -
+ + + Name + Value + + {#each execution.requestHeaders as header} + + + {header.key} + + + {header.value} + + + {/each} + {/if}

@@ -379,23 +363,22 @@ {/if} {:else if selectedResponse === 'headers'} {#if execution.responseHeaders.length} - - - Name - Value - - - {#each execution.responseHeaders as header} - - - {header.name} - - {header.value} - - {/each} - - + + + Name + Value + + {#each execution.responseHeaders as header} + + + {header.key} + + + {header.value} + + + {/each} + {/if}

{execution.responseHeaders?.length diff --git a/src/lib/pages/domains/wizard/step1.svelte b/src/lib/pages/domains/wizard/step1.svelte index 5a7150194..0e8750d15 100644 --- a/src/lib/pages/domains/wizard/step1.svelte +++ b/src/lib/pages/domains/wizard/step1.svelte @@ -1,6 +1,5 @@ @@ -133,44 +124,49 @@

-
- -
-
- - For more details on our plans, visit our - pricing page. - - -
- {#if selectedPlan !== BillingPlan.FREE} -
- + +
+
- - {#if !selectedCoupon?.code} - +
+ + For more details on our plans, visit our + pricing page. + + +
+ {#if selectedPlan !== BillingPlan.FREE} + +
+ +
+ {#if !selectedCoupon?.code} + + {/if} {/if} - {/if} +
{#if selectedPlan !== BillingPlan.FREE} diff --git a/src/routes/(console)/create-organization/+page.ts b/src/routes/(console)/create-organization/+page.ts index 68b4c3a15..6c3cfe2f0 100644 --- a/src/routes/(console)/create-organization/+page.ts +++ b/src/routes/(console)/create-organization/+page.ts @@ -6,7 +6,10 @@ import type { Organization } from '$lib/stores/organization'; export const load: PageLoad = async ({ url, parent }) => { const { organizations } = await parent(); - const coupon = await getCoupon(url); + const [coupon, paymentMethods] = await Promise.all([ + getCoupon(url), + sdk.forConsole.billing.listPaymentMethods() + ]); let plan = getPlanFromUrl(url); const hasFreeOrganizations = organizations.teams?.some( (org) => (org as Organization)?.billingPlan === BillingPlan.FREE @@ -19,6 +22,7 @@ export const load: PageLoad = async ({ url, parent }) => { plan, coupon, hasFreeOrganizations, + paymentMethods, name: url.searchParams.get('name') ?? '' }; }; diff --git a/src/routes/(console)/createOrganization.svelte b/src/routes/(console)/createOrganization.svelte index 6547a5c51..9896ef451 100644 --- a/src/routes/(console)/createOrganization.svelte +++ b/src/routes/(console)/createOrganization.svelte @@ -8,9 +8,9 @@ import { Dependencies } from '$lib/constants'; import { Submit, trackEvent, trackError } from '$lib/actions/analytics'; import { ID } from '@appwrite.io/console'; - import Alert from '$lib/components/alert.svelte'; import { isCloud } from '$lib/system'; import { base } from '$app/paths'; + import { Alert } from '@appwrite.io/pink-svelte'; export let show = false; @@ -39,18 +39,17 @@ } - + {#if isCloud} - - Get ready for Appwrite Pro + We will soon introduce the much-anticipated Pro plan. Your account will continue to have access to one free organization. If you manage more than one organization, you will need to either upgrade to the Pro plan, transfer your projects to a Pro organization, or migrate to self-hosting. - + - + {/if} {#if $failedInvoice} {#if $failedInvoice?.lastError} - + The scheduled payment for {$organization.name} failed due to following error: {$failedInvoice.lastError} - + - + {:else} - - - The scheduled payment for {$organization.name} failed - - To avoid service disruptions in organization's your projects, please verify your payment - details and update them if necessary. - + + To avoid service disruptions in organization's your projects, please verify your + payment details and update them if necessary. + {/if} {/if} {#if defaultPaymentMethod?.failed && !backupPaymentMethod} - - - The default payment method for {$organization.name} has expired - + To avoid service disruptions in your organization's projects, please update your payment details. - + {/if} {#if $organization?.billingPlanDowngrade} - + Your organization will change to a {tierToPlan($organization?.billingPlanDowngrade) .name} plan once your current billing cycle ends and your invoice is paid on {toLocaleDate( $organization.billingNextInvoiceDate )}. - + {/if} -
- Billing -
+ Billing - +
diff --git a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte index 5b8cf737f..8fc9c44f4 100644 --- a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte +++ b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte @@ -34,8 +34,9 @@ let showExitModal = false; let formComponent: Form; let isSubmitting = writable(false); - let methods: PaymentList; - let paymentMethodId: string; + let paymentMethodId: string = + data.organization.paymentMethodId ?? + data.paymentMethods.paymentMethods.find((method) => !!method?.last4)?.$id; let collaborators: string[] = data?.members?.memberships ?.map((m) => { @@ -52,15 +53,6 @@ previousPage = from?.url?.pathname || previousPage; }); - async function loadPaymentMethods() { - methods = await sdk.forConsole.billing.listPaymentMethods(); - - paymentMethodId = - data.organization.paymentMethodId ?? - methods.paymentMethods.find((method) => !!method?.last4)?.$id ?? - null; - } - async function handleSubmit() { if (isDowngrade) { await downgrade(); @@ -184,10 +176,9 @@ $: isUpgrade = data.plan > data.organization.billingPlan; $: isDowngrade = data.plan < data.organization.billingPlan; - $: if (selectedPlan !== BillingPlan.FREE) { - loadPaymentMethods(); - } $: isButtonDisabled = $organization.billingPlan === selectedPlan; + + $: console.log(data.paymentMethods); @@ -248,6 +239,10 @@ {#if selectedPlan !== BillingPlan.FREE && data.organization.billingPlan === BillingPlan.FREE} +
- {#if !selectedCoupon?.code} - + + {:else}