diff --git a/src/lib/commandCenter/searchers/organizations.ts b/src/lib/commandCenter/searchers/organizations.ts index c24f38799e..9df8003a17 100644 --- a/src/lib/commandCenter/searchers/organizations.ts +++ b/src/lib/commandCenter/searchers/organizations.ts @@ -1,16 +1,10 @@ +import { resolve } from '$app/paths'; import { goto } from '$app/navigation'; -import { base } from '$app/paths'; -import { sdk } from '$lib/stores/sdk'; import type { Searcher } from '../commands'; -import { isCloud } from '$lib/system'; -import { Platform, Query } from '@appwrite.io/console'; +import { getTeamOrOrganizationList } from '$lib/stores/organization'; export const orgSearcher = (async (query: string) => { - const { teams } = !isCloud - ? await sdk.forConsole.teams.list() - : await sdk.forConsole.billing.listOrganization([ - Query.equal('platform', Platform.Appwrite) - ]); + const { teams } = await getTeamOrOrganizationList(); return teams .filter((organization) => organization.name.toLowerCase().includes(query.toLowerCase())) @@ -18,7 +12,11 @@ export const orgSearcher = (async (query: string) => { return { label: organization.name, callback: () => { - goto(`${base}/organization-${organization.$id}`); + goto( + resolve('/(console)/organization-[organization]', { + organization: organization.$id + }) + ); }, group: 'organizations' } as const; diff --git a/src/lib/components/archiveProject.svelte b/src/lib/components/archiveProject.svelte index 8eb3795914..8a324b395b 100644 --- a/src/lib/components/archiveProject.svelte +++ b/src/lib/components/archiveProject.svelte @@ -38,23 +38,21 @@ import { isSmallViewport } from '$lib/stores/viewport'; import { isCloud } from '$lib/system'; import { regions as regionsStore } from '$lib/stores/organization'; - import type { Organization } from '$lib/stores/organization'; - import type { Plan } from '$lib/sdk/billing'; // props interface Props { + currentPlan: Models.BillingPlan; + organization: Models.Organization; projectsToArchive: Models.Project[]; - organization: Organization; - currentPlan: Plan; archivedTotalOverall: number; archivedOffset: number; limit: number; } let { - projectsToArchive, - organization, currentPlan, + organization, + projectsToArchive, archivedTotalOverall, archivedOffset, limit diff --git a/src/lib/components/billing/alerts/limitReached.svelte b/src/lib/components/billing/alerts/limitReached.svelte index 4885db75e1..12605cded4 100644 --- a/src/lib/components/billing/alerts/limitReached.svelte +++ b/src/lib/components/billing/alerts/limitReached.svelte @@ -5,16 +5,21 @@ 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, + readOnly, + billingIdToPlan, + upgradeURL + } from '$lib/stores/billing'; import { organization } from '$lib/stores/organization'; {#if $organization?.$id && $organization?.billingPlan === BillingPlan.FREE && $readOnly && !hideBillingHeaderRoutes.includes(page.url.pathname)} + title={`${$organization.name} usage has reached the ${billingIdToPlan($organization.billingPlan).name} plan limit`}> - Usage for the {$organization.name} organization has reached the limits of the {tierToPlan( + Usage for the {$organization.name} organization has reached the limits of the {billingIdToPlan( $organization.billingPlan ).name} plan. Consider upgrading to increase your resource usage. diff --git a/src/lib/components/billing/alerts/paymentMandate.svelte b/src/lib/components/billing/alerts/paymentMandate.svelte new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/lib/components/billing/alerts/selectProjectCloud.svelte b/src/lib/components/billing/alerts/selectProjectCloud.svelte index 510334aa2e..a0084f97ab 100644 --- a/src/lib/components/billing/alerts/selectProjectCloud.svelte +++ b/src/lib/components/billing/alerts/selectProjectCloud.svelte @@ -31,10 +31,10 @@ async function updateSelected() { try { - await sdk.forConsole.billing.updateSelectedProjects( - projects[0].teamId, - selectedProjects - ); + await sdk.forConsole.organizations.updateProjects({ + organizationId, + projects: selectedProjects + }); showSelectProject = false; invalidate(Dependencies.ORGANIZATION); diff --git a/src/lib/components/billing/couponInput.svelte b/src/lib/components/billing/couponInput.svelte index 85e73411c0..fc33df37df 100644 --- a/src/lib/components/billing/couponInput.svelte +++ b/src/lib/components/billing/couponInput.svelte @@ -1,16 +1,16 @@ - + {#if children} + {@render children()} + {:else} Upgrade to add {service} - Upgrade to a {tierToPlan(BillingPlan.PRO).name} plan to add {service} to your organization + Upgrade to a {proPlanName} plan to add {service} to your organization - {#if methods.total} + {#if paymentMethods.total} {#each filteredPaymentMethods as paymentMethod} addPaymentMethod(paymentMethod?.$id)}> @@ -311,12 +321,17 @@ selectedPaymentMethod={isSelectedBackup ? backupMethod : primaryMethod} /> {/if} {#if isCloud && hasStripePublicKey} - + {/if} {#if showDelete && isCloud && hasStripePublicKey} {@const hasOtherMethod = isSelectedBackup ? !!organization?.paymentMethodId : !!organization?.backupPaymentMethodId} + r.resourceId === resourceId); + function getResource(resources: Array | undefined, resourceId: string) { + return resources?.find((resource) => resource.resourceId === resourceId); } function createRow({ @@ -221,7 +221,7 @@ function createResourceRow( id: string, label: string, - resource: InvoiceUsage | undefined, + resource: Models.UsageResources | undefined, planLimit: number | null | undefined, formatValue = formatNum ) { @@ -229,8 +229,8 @@ } function getBillingData( - currentPlan: Plan, - currentAggregation: AggregationTeam | undefined, + currentPlan: Models.BillingPlan, + currentAggregation: Models.AggregationTeam | undefined, isSmallViewport: boolean ) { // base plan row diff --git a/src/routes/(console)/organization-[organization]/billing/planSummaryOld.svelte b/src/routes/(console)/organization-[organization]/billing/planSummaryOld.svelte index 083aff4445..638f72b523 100644 --- a/src/routes/(console)/organization-[organization]/billing/planSummaryOld.svelte +++ b/src/routes/(console)/organization-[organization]/billing/planSummaryOld.svelte @@ -3,9 +3,8 @@ import { CardGrid } from '$lib/components'; import { Button } from '$lib/elements/forms'; import { toLocaleDate } from '$lib/helpers/date'; - import { plansInfo, upgradeURL } from '$lib/stores/billing'; + import { upgradeURL } from '$lib/stores/billing'; import { organization } from '$lib/stores/organization'; - import type { Aggregation, Invoice, Plan } from '$lib/sdk/billing'; import { abbreviateNumber, formatCurrency, formatNumberWithCommas } from '$lib/helpers/numbers'; import { BillingPlan } from '$lib/constants'; import { Click, trackEvent } from '$lib/actions/analytics'; @@ -20,18 +19,20 @@ } from '@appwrite.io/pink-svelte'; import { IconInfo, IconTag } from '@appwrite.io/pink-icons-svelte'; import CancelDowngradeModel from './cancelDowngradeModal.svelte'; + import type { Models } from '@appwrite.io/console'; - export let currentPlan: Plan; - export let currentInvoice: Invoice | undefined = undefined; + export let currentPlan: Models.BillingPlan; export let availableCredit: number | undefined = undefined; - export let currentAggregation: Aggregation | undefined = undefined; + export let currentInvoice: Models.Invoice | undefined = undefined; + export let currentAggregation: Models.AggregationTeam | undefined = undefined; let showCancel: boolean = false; const today = new Date(); const isTrial = new Date($organization?.billingStartDate).getTime() - today.getTime() > 0 && - $plansInfo.get($organization.billingPlan)?.trialDays; + $organization?.billingTrialDays; /* number of trial days. */ + const extraUsage = currentInvoice ? currentInvoice.amount - currentPlan?.price : 0; diff --git a/src/routes/(console)/organization-[organization]/billing/removeAddress.svelte b/src/routes/(console)/organization-[organization]/billing/removeAddress.svelte index 0a913b851b..52359ad2c1 100644 --- a/src/routes/(console)/organization-[organization]/billing/removeAddress.svelte +++ b/src/routes/(console)/organization-[organization]/billing/removeAddress.svelte @@ -14,7 +14,10 @@ async function removeAddress() { try { - await sdk.forConsole.billing.removeBillingAddress($organization.$id); + await sdk.forConsole.organizations.deleteBillingAddress({ + organizationId: $organization.$id + }); + addNotification({ type: 'success', message: `The billing address has been removed from ${$organization.name}` diff --git a/src/routes/(console)/organization-[organization]/billing/replaceAddress.svelte b/src/routes/(console)/organization-[organization]/billing/replaceAddress.svelte index 5ef49d0261..56798f55b3 100644 --- a/src/routes/(console)/organization-[organization]/billing/replaceAddress.svelte +++ b/src/routes/(console)/organization-[organization]/billing/replaceAddress.svelte @@ -6,7 +6,6 @@ import { organization } from '$lib/stores/organization'; import { Dependencies } from '$lib/constants'; import { onMount } from 'svelte'; - import type { AddressesList } from '$lib/sdk/billing'; import { addNotification } from '$lib/stores/notifications'; import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; import { base } from '$app/paths'; @@ -16,8 +15,9 @@ export let show = false; export let locale: Models.Locale; export let countryList: Models.CountryList; + let loading = true; - let addresses: AddressesList; + let addresses: Models.BillingAddressList; let selectedAddress: string; let error: string; let country: string; @@ -35,7 +35,7 @@ onMount(async () => { loading = true; - addresses = await sdk.forConsole.billing.listAddresses(); + addresses = await sdk.forConsole.account.listBillingAddresses(); const firstNonCurrentAddress = addresses?.billingAddresses?.find( (address) => address.$id !== $organization?.billingAddressId @@ -63,15 +63,19 @@ if (selectedAddress === $organization.billingAddressId) { show = false; } else if (selectedAddress === '$new') { - const address = await sdk.forConsole.billing.createAddress( + const address = await sdk.forConsole.account.createBillingAddress({ country, streetAddress, city, state, - postalCode ? postalCode : undefined, - addressLine2 ? postalCode : undefined - ); - await sdk.forConsole.billing.setBillingAddress($organization.$id, address.$id); + postalCode: postalCode ? postalCode : undefined, + addressLine2: addressLine2 ? addressLine2 : undefined + }); + + await sdk.forConsole.organizations.setBillingAddress({ + organizationId: $organization.$id, + billingAddressId: address.$id + }); invalidate(Dependencies.ORGANIZATION); invalidate(Dependencies.ADDRESS); @@ -86,7 +90,10 @@ message: `Your billing address has been updated` }); } else { - await sdk.forConsole.billing.setBillingAddress($organization.$id, selectedAddress); + await sdk.forConsole.organizations.setBillingAddress({ + organizationId: $organization.$id, + billingAddressId: selectedAddress + }); invalidate(Dependencies.ORGANIZATION); invalidate(Dependencies.ADDRESS); diff --git a/src/routes/(console)/organization-[organization]/billing/replaceCard.svelte b/src/routes/(console)/organization-[organization]/billing/replaceCard.svelte index 920f7b4741..847ebd016c 100644 --- a/src/routes/(console)/organization-[organization]/billing/replaceCard.svelte +++ b/src/routes/(console)/organization-[organization]/billing/replaceCard.svelte @@ -3,15 +3,14 @@ import { FakeModal } from '$lib/components'; import { Button } from '$lib/elements/forms'; import { sdk } from '$lib/stores/sdk'; - import type { Organization } from '$lib/stores/organization'; import { Dependencies } from '$lib/constants'; import { setPaymentMethod, submitStripeCard } from '$lib/stores/stripe'; import { onMount } from 'svelte'; - import type { PaymentList, PaymentMethodData } from '$lib/sdk/billing'; import { addNotification } from '$lib/stores/notifications'; import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; import { PaymentBoxes } from '$lib/components/billing'; - import type { PaymentMethod } from '@stripe/stripe-js'; + import type { PaymentMethod as StripePaymentMethod } from '@stripe/stripe-js'; + import type { Models } from '@appwrite.io/console'; let { show = $bindable(false), @@ -21,15 +20,15 @@ }: { show?: boolean; isBackup?: boolean; - methods: PaymentList; - organization: Organization; + methods: Models.PaymentMethodList; + organization: Models.Organization; } = $props(); let name: string | null = $state(null); let error: string | null = $state(null); let showState: boolean = $state(false); let countryState: string | null = $state(null); - let paymentMethod: PaymentMethod | null = $state(null); + let paymentMethod: StripePaymentMethod | null = $state(null); let selectedPaymentMethodId: string | null = $state(null); const filteredMethods = $derived(methods?.paymentMethods.filter((method) => !!method?.last4)); @@ -60,19 +59,19 @@ if (showState && !countryState) { throw Error('Please select a state'); } - let method: PaymentMethodData; + let method: Models.PaymentMethod; if (showState) { method = await setPaymentMethod(paymentMethod.id, name, countryState); } else { const card = await submitStripeCard(name, organization.$id); if (card && Object.hasOwn(card, 'id')) { - if ((card as PaymentMethod).card?.country === 'US') { - paymentMethod = card as PaymentMethod; + if ((card as StripePaymentMethod).card?.country === 'US') { + paymentMethod = card as StripePaymentMethod; showState = true; return; } } else if (card && Object.hasOwn(card, '$id')) { - method = card as PaymentMethodData; + method = card as Models.PaymentMethod; } } selectedPaymentMethodId = method.$id; @@ -97,10 +96,10 @@ async function addPaymentMethod(paymentMethodId: string) { try { - await sdk.forConsole.billing.setOrganizationPaymentMethod( - organization.$id, + await sdk.forConsole.organizations.setDefaultPaymentMethod({ + organizationId: organization.$id, paymentMethodId - ); + }); } catch (err) { error = err.message; } @@ -108,10 +107,10 @@ async function addBackupPaymentMethod(paymentMethodId: string) { try { - await sdk.forConsole.billing.setOrganizationPaymentMethodBackup( - organization.$id, + await sdk.forConsole.organizations.setBackupPaymentMethod({ + organizationId: organization.$id, paymentMethodId - ); + }); } catch (err) { error = err.message; } diff --git a/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte b/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte index 65e217d2c6..9f351e2cb1 100644 --- a/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte +++ b/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte @@ -3,7 +3,6 @@ import { FakeModal } from '$lib/components'; import { Button } from '$lib/elements/forms'; import { Dependencies } from '$lib/constants'; - import type { Invoice, PaymentMethodData } from '$lib/sdk/billing'; import { addNotification } from '$lib/stores/notifications'; import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; import { page } from '$app/state'; @@ -20,19 +19,22 @@ import { onMount } from 'svelte'; import { getApiEndpoint, sdk } from '$lib/stores/sdk'; import { formatCurrency } from '$lib/helpers/numbers'; - import { base } from '$app/paths'; - import type { PaymentMethod } from '@stripe/stripe-js'; + import { resolve } from '$app/paths'; + import type { PaymentMethod as StripePaymentMethod } from '@stripe/stripe-js'; + import type { Models } from '@appwrite.io/console'; export let show = false; - export let invoice: Invoice; + export let invoice: Models.Invoice | null = null; + + let name: string; + let state: string = ''; let error: string = null; + let setAsDefault = false; let isButtonDisabled = false; - let name: string; let paymentMethodId: string; - let setAsDefault = false; let showState: boolean = false; - let state: string = ''; - let paymentMethod: PaymentMethod | null = null; + let paymentMethod: StripePaymentMethod | null = null; + const endpoint = getApiEndpoint(); onMount(async () => { @@ -60,15 +62,15 @@ if (showState && !state) { throw Error('Please select a state'); } - let method: PaymentMethodData; + let method: Models.PaymentMethod; if (showState) { method = await setPaymentMethod(paymentMethod.id, name, state); } else { const card = await submitStripeCard(name, $organization.$id); // When Stripe returns an expanded PaymentMethod for US cards, we need state. - if (Object.hasOwn(card, 'id') && (card as PaymentMethod)?.card) { - if ((card as PaymentMethod).card?.country === 'US') { - paymentMethod = card as PaymentMethod; + if (Object.hasOwn(card, 'id') && (card as StripePaymentMethod)?.card) { + if ((card as StripePaymentMethod).card?.country === 'US') { + paymentMethod = card as StripePaymentMethod; showState = true; return; } @@ -76,10 +78,14 @@ // Otherwise, we expect an Appwrite PaymentMethodData with `$id`. if (Object.hasOwn(card, '$id')) { - method = card as PaymentMethodData; + method = card as Models.PaymentMethod; } } - const card = await sdk.forConsole.billing.getPaymentMethod(method.$id); + + const card = await sdk.forConsole.account.getPaymentMethod({ + paymentMethodId: method.$id + }); + if (card?.last4) { paymentMethodId = card.$id; } else { @@ -87,31 +93,45 @@ 'The payment method you selected is not valid. Please select a different one.' ); } - invalidate(Dependencies.PAYMENT_METHODS); + + await invalidate(Dependencies.PAYMENT_METHODS); } catch (e) { paymentMethodId = $organization.paymentMethodId; error = e.message; } } + if (setAsDefault) { - await sdk.forConsole.billing.setDefaultPaymentMethod(paymentMethodId); + await sdk.forConsole.organizations.setDefaultPaymentMethod({ + organizationId: $organization.$id, + paymentMethodId + }); } - const { clientSecret, status } = await sdk.forConsole.billing.retryPayment( - $organization.$id, - invoice.$id, - paymentMethodId - ); + + const { clientSecret, status } = + await sdk.forConsole.organizations.createInvoicePayment({ + organizationId: $organization.$id, + invoiceId: invoice.$id, + paymentMethodId + }); if (status !== 'succeeded' && status !== 'cancelled') { // probably still pending, confirm via stripe! - await confirmPayment( - $organization.$id, + const resolvedUrl = resolve('/(console)/organization-[organization]/billing', { + organization: $organization.$id + }); + + await confirmPayment({ clientSecret, - paymentMethodId ? paymentMethodId : $organization.paymentMethodId, - `${base}/organization-${$organization.$id}/billing?type=validate-invoice&invoice=${invoice.$id}` - ); + paymentMethodId: paymentMethodId ?? $organization.paymentMethodId, + orgId: $organization.$id, + route: `${resolvedUrl}?type=validate-invoice&invoice=${invoice.$id}` + }); - await sdk.forConsole.billing.updateInvoiceStatus($organization.$id, invoice.$id); + await sdk.forConsole.organizations.validateInvoice({ + organizationId: $organization.$id, + invoiceId: invoice.$id + }); } invalidate(Dependencies.ORGANIZATION); diff --git a/src/routes/(console)/organization-[organization]/billing/store.ts b/src/routes/(console)/organization-[organization]/billing/store.ts index a8f05930a9..e11b695153 100644 --- a/src/routes/(console)/organization-[organization]/billing/store.ts +++ b/src/routes/(console)/organization-[organization]/billing/store.ts @@ -1,11 +1,11 @@ import { page } from '$app/stores'; import { derived, writable } from 'svelte/store'; +import type { Models } from '@appwrite.io/console'; import type { WizardStepsType } from '$lib/layout/wizardWithSteps.svelte'; -import type { AggregationList, Invoice, InvoiceUsage } from '$lib/sdk/billing'; export const aggregationList = derived( page, - ($page) => $page.data.aggregationList as AggregationList + ($page) => $page.data.aggregationList as Models.AggregationTeamList ); export const addCreditWizardSteps = writable(new Map()); @@ -14,33 +14,33 @@ export const addCreditWizardStore = writable<{ coupon: string; paymentMethodId: paymentMethodId: null }); -export const selectedInvoice = writable(null); +export const selectedInvoice = writable(null); export const showRetryModal = writable(false); export type RowFactoryOptions = { id: string; label: string; - resource?: InvoiceUsage; + resource?: Models.UsageResources; planLimit?: number | null; includeProgress?: boolean; formatValue?: (value: number | null | undefined) => string; usageFormatter?: (options: { value: number; planLimit?: number | null; - resource?: InvoiceUsage; + resource?: Models.UsageResources; formatValue: (value: number | null | undefined) => string; hasLimit: boolean; }) => string; - priceFormatter?: (options: { amount: number; resource?: InvoiceUsage }) => string; + priceFormatter?: (options: { amount: number; resource?: Models.UsageResources }) => string; progressFactory?: (options: { value: number; planLimit?: number | null; - resource?: InvoiceUsage; + resource?: Models.UsageResources; hasLimit: boolean; }) => Array<{ size: number; color: string; tooltip?: { title: string; label: string } }>; maxFactory?: (options: { planLimit?: number | null; hasLimit: boolean; - resource?: InvoiceUsage; + resource?: Models.UsageResources; }) => number | null; }; diff --git a/src/routes/(console)/organization-[organization]/billing/taxId.svelte b/src/routes/(console)/organization-[organization]/billing/taxId.svelte index bbdb664796..bef6cc8444 100644 --- a/src/routes/(console)/organization-[organization]/billing/taxId.svelte +++ b/src/routes/(console)/organization-[organization]/billing/taxId.svelte @@ -17,7 +17,10 @@ async function updateTaxId() { try { - await sdk.forConsole.billing.updateTaxId($organization.$id, taxId); + await sdk.forConsole.organizations.setBillingTaxId({ + organizationId: $organization.$id, + taxId + }); await invalidate(Dependencies.ORGANIZATION); addNotification({ type: 'success', diff --git a/src/routes/(console)/organization-[organization]/billing/wizard/addCredit.svelte b/src/routes/(console)/organization-[organization]/billing/wizard/addCredit.svelte index d8933fa6b4..99ece582a8 100644 --- a/src/routes/(console)/organization-[organization]/billing/wizard/addCredit.svelte +++ b/src/routes/(console)/organization-[organization]/billing/wizard/addCredit.svelte @@ -1,24 +1,26 @@ - + + diff --git a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/+page.ts b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/+page.ts index fda7fb6a2a..2ed1fc7d71 100644 --- a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/+page.ts +++ b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/+page.ts @@ -1,18 +1,26 @@ -import { Dependencies } from '$lib/constants'; -import { sdk } from '$lib/stores/sdk'; import { isCloud } from '$lib/system'; -import { Query, Platform } from '@appwrite.io/console'; +import { redirect } from '@sveltejs/kit'; +import { resolve } from '$app/paths'; +import { Dependencies } from '$lib/constants'; +import type { Models } from '@appwrite.io/console'; +import { getTeamOrOrganizationList } from '$lib/stores/organization'; -export const load = async ({ parent, depends }) => { - depends(Dependencies.DOMAINS); +export const load = async ({ params, parent, depends }) => { + if (!isCloud) { + redirect( + 303, + resolve('/(console)/organization-[organization]', { + organization: params.organization + }) + ); + } - const organizations = !isCloud - ? await sdk.forConsole.teams.list() - : await sdk.forConsole.billing.listOrganization([ - Query.equal('platform', Platform.Appwrite) - ]); + depends(Dependencies.DOMAINS); const { domain } = await parent(); + + const organizations = (await getTeamOrOrganizationList()) as Models.OrganizationList; + return { domain, organizations diff --git a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte index 542ea62ad1..0ecaa38cb8 100644 --- a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte +++ b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte @@ -6,12 +6,12 @@ import { Dependencies } from '$lib/constants'; import { Button, InputSelect } from '$lib/elements/forms'; import { addNotification } from '$lib/stores/notifications'; - import type { OrganizationList } from '$lib/stores/organization'; import { sdk } from '$lib/stores/sdk'; import type { Models } from '@appwrite.io/console'; export let domain: Models.Domain; - export let organizations: OrganizationList; + export let organizations: Models.OrganizationList; + let selectedOrg: string = null; async function moveDomain() { diff --git a/src/routes/(console)/organization-[organization]/header.svelte b/src/routes/(console)/organization-[organization]/header.svelte index 191131ae49..ba61eccca1 100644 --- a/src/routes/(console)/organization-[organization]/header.svelte +++ b/src/routes/(console)/organization-[organization]/header.svelte @@ -11,16 +11,10 @@ import { daysLeftInTrial, getServiceLimit, - plansInfo, readOnly, - tierToPlan + billingIdToPlan } from '$lib/stores/billing'; - import { - members, - newMemberModal, - newOrgModal, - type Organization - } from '$lib/stores/organization'; + import { members, newMemberModal, newOrgModal } from '$lib/stores/organization'; import { canSeeBilling, canSeeProjects, @@ -31,6 +25,7 @@ import { GRACE_PERIOD_OVERRIDE, isCloud } from '$lib/system'; import { IconGithub, IconPlus, IconPlusSm } from '@appwrite.io/pink-icons-svelte'; import { Badge, Icon, Layout, Tooltip, Typography } from '@appwrite.io/pink-svelte'; + import type { Models } from '@appwrite.io/console'; let areMembersLimited: boolean = $state(false); @@ -42,7 +37,7 @@ (($readOnly && !GRACE_PERIOD_OVERRIDE) || (isLimited && $members?.total >= limit)); }); - const organization = $derived(page.data.organization as Organization); + const organization = $derived(page.data.organization as Models.Organization); const path = $derived(`${base}/organization-${organization.$id}`); const tabs = $derived( @@ -110,7 +105,7 @@ {:else if isCloud && organization?.billingPlan === BillingPlan.FREE} {/if} - {#if isCloud && organization?.billingTrialStartDate && $daysLeftInTrial > 0 && organization.billingPlan !== BillingPlan.FREE && $plansInfo.get(organization.billingPlan)?.trialDays} + {#if isCloud && organization?.billingTrialStartDate && $daysLeftInTrial > 0 && organization.billingPlan !== BillingPlan.FREE && organization?.billingTrialDays} @@ -153,7 +148,7 @@ {organization?.billingPlan === BillingPlan.FREE ? 'Upgrade to add more members' : `You've reached the members limit for the ${ - tierToPlan(organization?.billingPlan)?.name + billingIdToPlan(organization?.billingPlan)?.name } plan`} diff --git a/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/download/+page.ts b/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/download/+page.ts index de6e172699..3a0e31cbd3 100644 --- a/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/download/+page.ts +++ b/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/download/+page.ts @@ -4,7 +4,10 @@ import type { PageLoad } from './$types'; export const load: PageLoad = async ({ params }) => { // verify invoice exists - const invoice = await sdk.forConsole.billing.getInvoice(params.organization, params.invoiceId); + const invoice = await sdk.forConsole.organizations.getInvoice({ + organizationId: params.organization, + invoiceId: params.invoiceId + }); const endpoint = getApiEndpoint(); return redirect( diff --git a/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts b/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts index bfd0e5b082..3a4576785e 100644 --- a/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts +++ b/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts @@ -4,7 +4,11 @@ import type { PageLoad } from './$types'; export const load: PageLoad = async ({ params }) => { // verify invoice exists - const invoice = await sdk.forConsole.billing.getInvoice(params.organization, params.invoiceId); + const invoice = await sdk.forConsole.organizations.getInvoice({ + organizationId: params.organization, + invoiceId: params.invoiceId + }); + const endpoint = getApiEndpoint(); return redirect( diff --git a/src/routes/(console)/organization-[organization]/members/+page.svelte b/src/routes/(console)/organization-[organization]/members/+page.svelte index 05c3500802..c9ad661504 100644 --- a/src/routes/(console)/organization-[organization]/members/+page.svelte +++ b/src/routes/(console)/organization-[organization]/members/+page.svelte @@ -35,7 +35,7 @@ Tooltip } from '@appwrite.io/pink-svelte'; import { BillingPlan } from '$lib/constants'; - import { tierToPlan } from '$lib/stores/billing'; + import { billingIdToPlan } from '$lib/stores/billing'; export let data; @@ -92,7 +92,7 @@ {$organization?.billingPlan === BillingPlan.FREE ? 'Upgrade to add more members' : `You've reached the members limit for the ${ - tierToPlan($organization?.billingPlan)?.name + billingIdToPlan($organization?.billingPlan)?.name } plan`} diff --git a/src/routes/(console)/organization-[organization]/settings/+page.ts b/src/routes/(console)/organization-[organization]/settings/+page.ts index 42c229dd9d..1f377bfe33 100644 --- a/src/routes/(console)/organization-[organization]/settings/+page.ts +++ b/src/routes/(console)/organization-[organization]/settings/+page.ts @@ -12,7 +12,11 @@ export const load: PageLoad = async ({ depends, params, parent }) => { sdk.forConsole.projects.list({ queries: [Query.equal('teamId', params.organization), Query.select(['$id', 'name'])] }), - isCloud ? sdk.forConsole.billing.listInvoices(params.organization) : undefined + isCloud + ? sdk.forConsole.organizations.listInvoices({ + organizationId: params.organization + }) + : undefined ]); return { diff --git a/src/routes/(console)/organization-[organization]/settings/deleteOrganizationEstimation.svelte b/src/routes/(console)/organization-[organization]/settings/deleteOrganizationEstimation.svelte index e521985a52..14ae7d8bcb 100644 --- a/src/routes/(console)/organization-[organization]/settings/deleteOrganizationEstimation.svelte +++ b/src/routes/(console)/organization-[organization]/settings/deleteOrganizationEstimation.svelte @@ -1,8 +1,9 @@ {#if estimation} diff --git a/src/routes/(console)/organization-[organization]/settings/deleteOrganizationModal.svelte b/src/routes/(console)/organization-[organization]/settings/deleteOrganizationModal.svelte index 135d9b68c4..51a1d483aa 100644 --- a/src/routes/(console)/organization-[organization]/settings/deleteOrganizationModal.svelte +++ b/src/routes/(console)/organization-[organization]/settings/deleteOrganizationModal.svelte @@ -12,23 +12,25 @@ import { toLocaleDate } from '$lib/helpers/date'; import { isCloud } from '$lib/system'; import { formatCurrency } from '$lib/helpers/numbers'; - import { tierToPlan } from '$lib/stores/billing'; + import { billingIdToPlan } from '$lib/stores/billing'; import { Table, Tabs, Alert } from '@appwrite.io/pink-svelte'; import DeleteOrganizationEstimation from './deleteOrganizationEstimation.svelte'; - import type { EstimationDeleteOrganization, InvoiceList } from '$lib/sdk/billing'; + import type { Models } from '@appwrite.io/console'; export let showDelete = false; - export let invoices: InvoiceList; + export let invoices: Models.InvoiceList; let error: string = null; let selectedTab = 'projects'; let organizationName: string = null; - let estimation: EstimationDeleteOrganization; + let estimation: Models.EstimationDeleteOrganization; async function deleteOrg() { try { if (isCloud) { - await sdk.forConsole.billing.deleteOrganization($organization.$id); + await sdk.forConsole.organizations.delete({ + organizationId: $organization.$id + }); } else { await sdk.forConsole.teams.delete({ teamId: $organization.$id @@ -82,9 +84,9 @@ if (isCloud) { try { error = ''; - estimation = await sdk.forConsole.billing.estimationDeleteOrganization( - $organization.$id - ); + estimation = await sdk.forConsole.organizations.estimationDeleteOrganization({ + organizationId: $organization.$id + }); } catch (e) { error = e.message; } @@ -97,7 +99,7 @@ + ${billingIdToPlan(upcomingInvoice.plan).name} plan`}> By proceeding, your invoice will be processed within the hour. Upon successful payment, your organization will be deleted. @@ -112,7 +114,8 @@ This action is irreversible. {/if}

- {#if estimation && (estimation.unpaidInvoices.length > 0 || estimation.grossAmount > 0)} + + {#if estimation && (estimation.unpaidInvoices.length > 0 || estimation.unpaidInvoices.some((invoice) => invoice.grossAmount > 0))} {:else} {#if $projects.total > 0} diff --git a/src/routes/(console)/organization-[organization]/settings/invoicesTable.svelte b/src/routes/(console)/organization-[organization]/settings/invoicesTable.svelte index 84b7ca6093..514e8a575a 100644 --- a/src/routes/(console)/organization-[organization]/settings/invoicesTable.svelte +++ b/src/routes/(console)/organization-[organization]/settings/invoicesTable.svelte @@ -1,5 +1,4 @@ diff --git a/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.ts b/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.ts index e5e1ee5a6c..0efb7c6020 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.ts +++ b/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.ts @@ -1,53 +1,59 @@ -import type { AggregationTeam, Invoice, InvoiceUsage } from '$lib/sdk/billing'; -import { accumulateUsage } from '$lib/sdk/usage'; import { sdk } from '$lib/stores/sdk'; -import { Query } from '@appwrite.io/console'; import type { PageLoad } from './$types'; +import { accumulateUsage } from '$lib/sdk/usage'; +import { type Models, Query } from '@appwrite.io/console'; export const load: PageLoad = async ({ params, parent }) => { - const { invoice, project, region } = params; + const { invoice: invoiceId, project, region } = params; const { organization } = await parent(); let startDate: string = organization.billingCurrentInvoiceDate; let endDate: string = organization.billingNextInvoiceDate; - let currentInvoice: Invoice = undefined; - let currentAggregation: AggregationTeam = undefined; + let currentInvoice: Models.Invoice = undefined; + let currentAggregation: Models.AggregationTeam = undefined; - if (invoice) { - currentInvoice = await sdk.forConsole.billing.getInvoice(organization.$id, invoice); - currentAggregation = await sdk.forConsole.billing.getAggregation( - organization.$id, - currentInvoice.aggregationId - ); + if (invoiceId) { + currentInvoice = await sdk.forConsole.organizations.getInvoice({ + organizationId: organization.$id, + invoiceId + }); + currentAggregation = await sdk.forConsole.organizations.getAggregation({ + organizationId: organization.$id, + aggregationId: currentInvoice.aggregationId + }); startDate = currentInvoice.from; endDate = currentInvoice.to; } else { try { - currentAggregation = await sdk.forConsole.billing.getAggregation( - organization.$id, - organization.billingAggregationId - ); + currentAggregation = await sdk.forConsole.organizations.getAggregation({ + organizationId: organization.$id, + aggregationId: organization.billingAggregationId + }); } catch (e) { // ignore error if no aggregation found } } const [invoices, usage] = await Promise.all([ - sdk.forConsole.billing.listInvoices(organization.$id, [Query.orderDesc('from')]), + sdk.forConsole.organizations.listInvoices({ + organizationId: organization.$id, + queries: [Query.orderDesc('from')] + }), sdk.forProject(region, project).project.getUsage({ startDate, endDate }) ]); if (currentAggregation) { - let projectSpecificData = null; + let projectSpecificData: Models.AggregationBreakdown | null = null; if (currentAggregation.breakdown) { projectSpecificData = currentAggregation.breakdown.find((p) => p.$id === project); } if (projectSpecificData) { const executionsResource = projectSpecificData.resources?.find?.( - (r: InvoiceUsage) => r.resourceId === 'executions' + (resource) => resource.resourceId === 'executions' ); + if (executionsResource) { usage.executionsTotal = executionsResource.value || usage.executionsTotal; } diff --git a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte index f0b24c0605..d0d4a0b0d6 100644 --- a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte +++ b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/settings/updateMaxFileSize.svelte @@ -10,11 +10,10 @@ import { organization } from '$lib/stores/organization'; import { GRACE_PERIOD_OVERRIDE, isCloud } from '$lib/system'; import { updateBucket } from './+page.svelte'; - import type { Plan } from '$lib/sdk/billing'; import type { Models } from '@appwrite.io/console'; export let bucket: Models.Bucket; - export let currentPlan: Plan | null; + export let currentPlan: Models.BillingPlan | null; const service = currentPlan ? currentPlan['fileSize'] : null; const { value, unit, baseValue, units } = createByteUnitPair(bucket.maximumFileSize, 1000); diff --git a/src/routes/(console)/regions.ts b/src/routes/(console)/regions.ts index 32dbd0308e..404ee92096 100644 --- a/src/routes/(console)/regions.ts +++ b/src/routes/(console)/regions.ts @@ -21,10 +21,11 @@ export async function loadAvailableRegions(orgId: string, force: boolean = false return; } - // TODO: @itznotabug, @torstendittmann we need a better way for this! - const availableRegions = await sdk.forConsole.billing.listRegions(orgId); - regions.set(availableRegions); + const availableRegions = await sdk.forConsole.console.getRegions({ + organizationId: orgId + }); + regions.set(availableRegions); lastLoadedOrganization = orgId; } catch (error) { console.error(`Failed to load regions for teamId: ${orgId}`, error); diff --git a/src/routes/(console)/store.ts b/src/routes/(console)/store.ts index 359a71b30f..a21c994510 100644 --- a/src/routes/(console)/store.ts +++ b/src/routes/(console)/store.ts @@ -1,6 +1,5 @@ import { page } from '$app/stores'; import type { HeaderAlert } from '$lib/stores/headerAlert'; -import type { Organization } from '$lib/stores/organization'; import type { Models } from '@appwrite.io/console'; import { derived, writable } from 'svelte/store'; @@ -16,4 +15,4 @@ export const protocol = derived(consoleVariables, ($vars) => ); export const activeHeaderAlert = writable(null); -export const orgMissingPaymentMethod = writable(null); +export const orgMissingPaymentMethod = writable(null); diff --git a/src/routes/(public)/(guest)/login/+page.ts b/src/routes/(public)/(guest)/login/+page.ts index 33d808b7e5..5aac9163a0 100644 --- a/src/routes/(public)/(guest)/login/+page.ts +++ b/src/routes/(public)/(guest)/login/+page.ts @@ -1,34 +1,40 @@ -import { base } from '$app/paths'; -import type { Campaign } from '$lib/stores/campaigns'; +import { resolve } from '$app/paths'; import { sdk } from '$lib/stores/sdk'; import { redirect } from '@sveltejs/kit'; import type { PageLoad } from './$types'; +import type { Models } from '@appwrite.io/console'; export const load: PageLoad = async ({ url }) => { if (url.searchParams.has('code')) { const code = url.searchParams.get('code'); - let campaign: Campaign; + let campaign: Models.Campaign; try { - const couponData = await sdk.forConsole.billing.getCoupon(code); + const couponData = await sdk.forConsole.console.getCoupon({ + couponId: code + }); + if (couponData.campaign) { - campaign = await sdk.forConsole.billing.getCampaign(couponData.campaign); + campaign = await sdk.forConsole.console.getCampaign({ + campaignId: couponData.campaign + }); return { couponData, campaign }; - } else redirect(303, `${base}/login`); + } else redirect(303, resolve('/login')); } catch (e) { - redirect(303, `${base}/login`); + redirect(303, resolve('/login')); } } + if (url.searchParams.has('campaign')) { const campaignId = url.searchParams.get('campaign'); - let campaign: Campaign; + let campaign: Models.Campaign; try { - campaign = await sdk.forConsole.billing.getCampaign(campaignId); + campaign = await sdk.forConsole.console.getCampaign({ campaignId }); return { campaign }; } catch (e) { - redirect(303, `${base}/login`); + redirect(303, resolve('/login')); } } return; diff --git a/src/routes/(public)/(guest)/register/+page.ts b/src/routes/(public)/(guest)/register/+page.ts index 1fa2e79de8..6f3dfe81ef 100644 --- a/src/routes/(public)/(guest)/register/+page.ts +++ b/src/routes/(public)/(guest)/register/+page.ts @@ -1,34 +1,40 @@ -import { base } from '$app/paths'; -import type { Campaign } from '$lib/stores/campaigns.js'; +import { resolve } from '$app/paths'; import { sdk } from '$lib/stores/sdk'; import { redirect } from '@sveltejs/kit'; import type { PageLoad } from './$types'; +import type { Models } from '@appwrite.io/console'; export const load: PageLoad = async ({ url }) => { if (url.searchParams.has('code')) { const code = url.searchParams.get('code'); - let campaign: Campaign; + let campaign: Models.Campaign; try { - const couponData = await sdk.forConsole.billing.getCoupon(code); + const couponData = await sdk.forConsole.console.getCoupon({ + couponId: code + }); + if (couponData.campaign) { - campaign = await sdk.forConsole.billing.getCampaign(couponData.campaign); + campaign = await sdk.forConsole.console.getCampaign({ + campaignId: couponData.campaign + }); return { couponData, campaign }; - } else redirect(303, `${base}/register`); + } else redirect(303, resolve('/register')); } catch (e) { - redirect(303, `${base}/register`); + redirect(303, resolve('/register')); } } + if (url.searchParams.has('campaign')) { const campaignId = url.searchParams.get('campaign'); - let campaign: Campaign; + let campaign: Models.Campaign; try { - campaign = await sdk.forConsole.billing.getCampaign(campaignId); + campaign = await sdk.forConsole.console.getCampaign({ campaignId }); return { campaign }; } catch (e) { - redirect(303, `${base}/register`); + redirect(303, resolve('/register')); } } return; diff --git a/src/routes/(public)/functions/deploy/+page.svelte b/src/routes/(public)/functions/deploy/+page.svelte index 0399cf3a3e..53ba37ece0 100644 --- a/src/routes/(public)/functions/deploy/+page.svelte +++ b/src/routes/(public)/functions/deploy/+page.svelte @@ -5,7 +5,6 @@ import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; import CustomId from '$lib/components/customId.svelte'; import { Button, Form, InputSelect } from '$lib/elements/forms'; - import type { AllowedRegions } from '$lib/sdk/billing.js'; import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; import { isCloud } from '$lib/system'; @@ -24,6 +23,7 @@ import { filterRegions } from '$lib/helpers/regions'; import { loadAvailableRegions } from '$routes/(console)/regions'; import { regions as regionsStore } from '$lib/stores/organization'; + import type { AllowedRegions } from '$lib/sdk/billing'; let { data } = $props(); diff --git a/src/routes/(public)/functions/deploy/+page.ts b/src/routes/(public)/functions/deploy/+page.ts index d91d084ff8..929de33ec1 100644 --- a/src/routes/(public)/functions/deploy/+page.ts +++ b/src/routes/(public)/functions/deploy/+page.ts @@ -2,12 +2,12 @@ import { sdk } from '$lib/stores/sdk.js'; import { redirect } from '@sveltejs/kit'; import { base } from '$app/paths'; import { isCloud } from '$lib/system'; -import { BillingPlan } from '$lib/constants'; -import { ID, type Models, Query, Platform } from '@appwrite.io/console'; -import type { OrganizationList } from '$lib/stores/organization'; +import { BillingPlanGroup, ID } from '@appwrite.io/console'; +import { getTeamOrOrganizationList } from '$lib/stores/organization'; import { redirectTo } from '$routes/store'; import type { PageLoad } from './$types'; import { getRepositoryInfo } from '$lib/helpers/github'; +import { getBasePlanFromGroup } from '$lib/stores/billing'; export const load: PageLoad = async ({ parent, url }) => { const { account } = await parent(); @@ -64,24 +64,16 @@ export const load: PageLoad = async ({ parent, url }) => { deploymentData.repository.owner = info.owner; // Get organizations - let organizations: Models.TeamList> | OrganizationList | undefined; - if (isCloud) { - organizations = await sdk.forConsole.billing.listOrganization([ - Query.equal('platform', Platform.Appwrite) - ]); - } else { - organizations = await sdk.forConsole.teams.list(); - } + let organizations = await getTeamOrOrganizationList(); if (!organizations?.total) { try { if (isCloud) { - await sdk.forConsole.billing.createOrganization( - ID.unique(), - 'Personal Projects', - BillingPlan.FREE, - null - ); + await sdk.forConsole.organizations.create({ + organizationId: ID.unique(), + name: 'Personal Projects', + billingPlan: getBasePlanFromGroup(BillingPlanGroup.Starter).$id + }); } else { await sdk.forConsole.teams.create({ teamId: ID.unique(), @@ -89,13 +81,7 @@ export const load: PageLoad = async ({ parent, url }) => { }); } - if (isCloud) { - organizations = await sdk.forConsole.billing.listOrganization([ - Query.equal('platform', Platform.Appwrite) - ]); - } else { - organizations = await sdk.forConsole.teams.list(); - } + organizations = await getTeamOrOrganizationList(); } catch (e) { console.error('Failed to create default organization:', e); } diff --git a/src/routes/(public)/sites/deploy/+page.svelte b/src/routes/(public)/sites/deploy/+page.svelte index 0d258793ac..c3d928dba8 100644 --- a/src/routes/(public)/sites/deploy/+page.svelte +++ b/src/routes/(public)/sites/deploy/+page.svelte @@ -6,7 +6,6 @@ import CustomId from '$lib/components/customId.svelte'; import { SvgIcon } from '$lib/components/index.js'; import { Button, Form, InputSelect } from '$lib/elements/forms'; - import type { AllowedRegions } from '$lib/sdk/billing.js'; import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; import { getFrameworkIcon } from '$lib/stores/sites.js'; @@ -28,6 +27,7 @@ import { filterRegions } from '$lib/helpers/regions'; import { loadAvailableRegions } from '$routes/(console)/regions'; import { regions as regionsStore } from '$lib/stores/organization'; + import type { AllowedRegions } from '$lib/sdk/billing'; let { data } = $props(); diff --git a/src/routes/(public)/sites/deploy/+page.ts b/src/routes/(public)/sites/deploy/+page.ts index ca57d36e34..1dc13b44fa 100644 --- a/src/routes/(public)/sites/deploy/+page.ts +++ b/src/routes/(public)/sites/deploy/+page.ts @@ -2,12 +2,12 @@ import { sdk } from '$lib/stores/sdk.js'; import { redirect, error } from '@sveltejs/kit'; import { base } from '$app/paths'; import { isCloud } from '$lib/system'; -import { BillingPlan } from '$lib/constants'; -import { ID, type Models, Query, Platform } from '@appwrite.io/console'; -import type { OrganizationList } from '$lib/stores/organization'; +import { BillingPlanGroup, ID, type Models } from '@appwrite.io/console'; +import { getTeamOrOrganizationList } from '$lib/stores/organization'; import { redirectTo } from '$routes/store'; import type { PageLoad } from './$types'; import { getRepositoryInfo } from '$lib/helpers/github'; +import { getBasePlanFromGroup } from '$lib/stores/billing'; export const load: PageLoad = async ({ parent, url }) => { const { account } = await parent(); @@ -80,25 +80,16 @@ export const load: PageLoad = async ({ parent, url }) => { }; } - let organizations: Models.TeamList> | OrganizationList | undefined; - - if (isCloud) { - organizations = await sdk.forConsole.billing.listOrganization([ - Query.equal('platform', Platform.Appwrite) - ]); - } else { - organizations = await sdk.forConsole.teams.list(); - } + let organizations = await getTeamOrOrganizationList(); if (!organizations?.total) { try { if (isCloud) { - await sdk.forConsole.billing.createOrganization( - ID.unique(), - 'Personal Projects', - BillingPlan.FREE, - null - ); + await sdk.forConsole.organizations.create({ + organizationId: ID.unique(), + name: 'Personal Projects', + billingPlan: getBasePlanFromGroup(BillingPlanGroup.Starter).$id + }); } else { await sdk.forConsole.teams.create({ teamId: ID.unique(), @@ -107,13 +98,7 @@ export const load: PageLoad = async ({ parent, url }) => { } // Refetch organizations after creation - if (isCloud) { - organizations = await sdk.forConsole.billing.listOrganization([ - Query.equal('platform', Platform.Appwrite) - ]); - } else { - organizations = await sdk.forConsole.teams.list(); - } + organizations = await getTeamOrOrganizationList(); } catch (e) { console.error('Failed to create default organization:', e); } diff --git a/src/routes/(public)/template-[template]/+page.svelte b/src/routes/(public)/template-[template]/+page.svelte index 600914e154..6ef3da9c7e 100644 --- a/src/routes/(public)/template-[template]/+page.svelte +++ b/src/routes/(public)/template-[template]/+page.svelte @@ -4,7 +4,6 @@ import CustomId from '$lib/components/customId.svelte'; import { SvgIcon } from '$lib/components/index.js'; import { Button, Form, InputSelect } from '$lib/elements/forms'; - import type { AllowedRegions } from '$lib/sdk/billing.js'; import { app } from '$lib/stores/app'; import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; @@ -23,6 +22,7 @@ Typography } from '@appwrite.io/pink-svelte'; import { filterRegions } from '$lib/helpers/regions'; + import type { AllowedRegions } from '$lib/sdk/billing'; let { data } = $props(); diff --git a/src/routes/(public)/template-[template]/+page.ts b/src/routes/(public)/template-[template]/+page.ts index e2dac3adfa..f9516d960e 100644 --- a/src/routes/(public)/template-[template]/+page.ts +++ b/src/routes/(public)/template-[template]/+page.ts @@ -1,11 +1,11 @@ -import { BillingPlan } from '$lib/constants.js'; +import { base } from '$app/paths'; import { sdk } from '$lib/stores/sdk.js'; -import { ID, type Models, Query, Platform } from '@appwrite.io/console'; import { isCloud } from '$lib/system.js'; -import { error, redirect } from '@sveltejs/kit'; -import type { OrganizationList } from '$lib/stores/organization.js'; import { redirectTo } from '$routes/store.js'; -import { base } from '$app/paths'; +import { error, redirect } from '@sveltejs/kit'; +import { getBasePlanFromGroup } from '$lib/stores/billing'; +import { getTeamOrOrganizationList } from '$lib/stores/organization.js'; +import { BillingPlanGroup, ID, type Models } from '@appwrite.io/console'; export const load = async ({ parent, url, params }) => { const { account } = await parent(); @@ -37,24 +37,14 @@ export const load = async ({ parent, url, params }) => { error(404, 'Type is not valid'); } - let organizations: Models.TeamList> | OrganizationList | undefined; - if (isCloud) { - organizations = account?.$id - ? await sdk.forConsole.billing.listOrganization([ - Query.equal('platform', Platform.Appwrite) - ]) - : undefined; - } else { - organizations = account?.$id ? await sdk.forConsole.teams.list() : undefined; - } + const organizations = account?.$id ? await getTeamOrOrganizationList() : undefined; if (!organizations?.total && account?.$id) { - await sdk.forConsole.billing.createOrganization( - ID.unique(), - 'Personal project', - BillingPlan.FREE, - null - ); + await sdk.forConsole.organizations.create({ + organizationId: ID.unique(), + name: 'Personal project', + billingPlan: getBasePlanFromGroup(BillingPlanGroup.Starter).$id + }); } return { diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index c1d724892f..2a80bb1e00 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -69,11 +69,16 @@ if (page.url.searchParams.has('code')) { const code = page.url.searchParams.get('code'); - const coupon = await sdk.forConsole.billing.getCoupon(code).catch(() => null); + const coupon = await sdk.forConsole.console + .getCoupon({ + couponId: code + }) + .catch(() => null); if (coupon?.campaign) { - const campaign = await sdk.forConsole.billing - .getCampaign(coupon.campaign) + const campaign = await sdk.forConsole.console + .getCampaign({ campaignId: coupon.campaign }) .catch(() => null); + if (campaign && $user) { goto(`${base}/apply-credit?${page.url.searchParams}`); loading.set(false); @@ -84,9 +89,10 @@ if ($user && page.url.searchParams.has('campaign')) { const campaignId = page.url.searchParams.get('campaign'); - const campaign = await sdk.forConsole.billing - .getCampaign(campaignId) + const campaign = await sdk.forConsole.console + .getCampaign({ campaignId }) .catch(() => null); + if (campaign) { goto(`${base}/apply-credit?${page.url.searchParams}`); diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index bcd3e307ff..5bdef81d7c 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -6,11 +6,14 @@ import { redirect } from '@sveltejs/kit'; import { Dependencies } from '$lib/constants'; import type { LayoutLoad } from './$types'; import { redirectTo } from './store'; -import { base, resolve } from '$app/paths'; +import { resolve } from '$app/paths'; import type { Account } from '$lib/stores/user'; -import { type AppwriteException, Query, Platform } from '@appwrite.io/console'; +import { type AppwriteException, Platform } from '@appwrite.io/console'; import { isCloud, VARS } from '$lib/system'; import { checkPricingRefAndRedirect } from '$lib/helpers/pricingRedirect'; +import { getTeamOrOrganizationList } from '$lib/stores/organization'; +import { makePlansMap } from '$lib/helpers/billing'; +import { plansInfo as plansInfoStore } from '$lib/stores/billing'; export const ssr = false; @@ -38,13 +41,13 @@ export const load: LayoutLoad = async ({ depends, url, route }) => { } } + const plansInfo = await getPlatformPlans(); + plansInfoStore.set(plansInfo); + return { + plansInfo, account: account, - organizations: !isCloud - ? await sdk.forConsole.teams.list() - : await sdk.forConsole.billing.listOrganization([ - Query.equal('platform', Platform.Appwrite) - ]) + organizations: await getTeamOrOrganizationList() }; } @@ -54,11 +57,13 @@ export const load: LayoutLoad = async ({ depends, url, route }) => { } if (error.type === 'user_more_factors_required') { - if (url.pathname === `${base}/mfa`) + const mfaUrl = resolve('/(authenticated)/mfa'); + + if (url.pathname === mfaUrl) return { mfaRequired: true }; - redirect(303, withParams(`${base}/mfa`, url.searchParams)); + redirect(303, withParams(mfaUrl, url.searchParams)); } if (!isPublicRoute) { @@ -66,7 +71,8 @@ export const load: LayoutLoad = async ({ depends, url, route }) => { checkPricingRefAndRedirect(url.searchParams, true); } - redirect(303, withParams(`${base}/login`, url.searchParams)); + const loginUrl = resolve('/(public)/(guest)/login'); + redirect(303, withParams(loginUrl, url.searchParams)); } }; @@ -74,3 +80,13 @@ function withParams(pathname: string, searchParams: URLSearchParams) { if (searchParams.size > 0) return `${pathname}?${searchParams.toString()}`; return pathname; } + +async function getPlatformPlans() { + if (!isCloud) return null; + + const plansArray = await sdk.forConsole.console.getPlans({ + platform: Platform.Appwrite + }); + + return makePlansMap(plansArray); +} diff --git a/src/routes/+page.ts b/src/routes/+page.ts index ea9e97cb82..e9600a4267 100644 --- a/src/routes/+page.ts +++ b/src/routes/+page.ts @@ -1,23 +1,24 @@ import { redirect } from '@sveltejs/kit'; -import { base } from '$app/paths'; +import { base, resolve } from '$app/paths'; import type { PageLoad } from './$types'; import { sdk } from '$lib/stores/sdk'; import { VARS } from '$lib/system'; const handleGithubEducationMembership = async (name: string, email: string) => { - const result = await sdk.forConsole.billing.setMembership('github-student-developer'); - if (result && 'error' in result) { - if (result.error.code === 409) { - redirect(303, `${base}/account/organizations`); + try { + await sdk.forConsole.console.createProgramMembership({ + programId: 'github-student-developer' + }); + + await setToGhStudentMailingList(name, email); + } catch (error) { + if (error.code === 409) { + redirect(303, resolve('/(console)/account/organizations')); } else { await sdk.forConsole.account.deleteSession({ sessionId: 'current' }); - redirect( - 303, - `${base}/education/error?message=${result.error.message}&code=${result.error.code}` - ); + const errorUrl = resolve('/(public)/(guest)/education/error'); + redirect(303, `${errorUrl}?message=${error.message}&code=${error.code}`); } - } else if (result && '$createdAt' in result) { - setToGhStudentMailingList(name, email); } }; @@ -35,7 +36,7 @@ export const load: PageLoad = async ({ parent, url }) => { if (userVisitedEducationPage()) { await handleGithubEducationMembership(account.name, account.email); - redirect(303, base); + redirect(303, resolve('/')); } else if (organizations.total && !isApplyingCredit) { const teamId = account.prefs.organization ?? organizations.teams[0].$id; if (!teamId) {